Не удается получить ответ от RxJava в модульном тестировании

#android #unit-testing #mockito #rx-java #rx-java2

#Android #модульное тестирование #mockito #rx-java #rx-java2

Вопрос:

Я попытался получить ответ от RxJava2 в модульном тестировании, я нашел пример, как это сделать, но я не вижу ответа, вы можете мне помочь? Спасибо. Сам код работает уже давно, без проблем, и когда потребовались тесты, я столкнулся с проблемой, похожие примеры более или менее одинаковы, но везде это делается таким образом, но у меня это не работает.

Там мой код от presenter:

   fun register(
    email: String,
    password: String,
    termsEnabled: Boolean,
    dayOfBirth: Int,
    monthOfBirth: Int,
    yearOfBirth: Int,
    formattedBirthDate: String,
    state: String?
) {
    addDisposable(
        registerUseCase.run(
            RegisterUseCase.RegisterRequest(
                email,
                password,
                termsEnabled,
                formattedBirthDate,
                state ?: ""
            )
        )
            .observeOn(mainThreadScheduler)
            .subscribeOn(backgroundScheduler)
            .subscribe(
                { 
                  getView?.showEmptyPassword()
                }, {
                 getView?.showEmptyPassword()
                    }
            )
    )
}
  

И проверить:

 @Before
fun setUp() {
    RxAndroidPlugins.setInitMainThreadSchedulerHandler { 
    Schedulers.trampoline() }
    MockitoAnnotations.initMocks(this)

    
    presenter = CreateAccountPresenter(
        mainThreadScheduler,
        backgroundScheduler,
        registerUseCase,
        getUserDataUseCase,
        getStatesUseCase,
        regexUtils,
        router,
        resourceUtils,
        deviceSharedPreferences
    )
    presenter.setView(view)
}


@Test
fun testRegister() {

    given(registerUseCase.run(RegisterUseCase.RegisterRequest(
        EMAIL, PASSWORD, true,
                FORMATTED_BIRTHDAY, STATE))
    ).willReturn(Single.just(RegisterResponse(false, "ok", "id")))

    presenter.register(
        EMAIL,
        PASSWORD,
        true,
        1,
        1,
        1,
        FORMATTED_BIRTHDAY,
        STATE)

    verify(view).showEmptyPassword()
}
  

Но проблема в том, что:

 Wanted but not invoked:
view.showEmptyPassword();
-> at 
com.unikrn.esports.umode.CreateAccountPresenterTest.testRegister(CreateAccountPresenterTest.kt:179)
Actually, there were zero interactions with this mock.
  

Комментарии:

1. Можете ли вы включить код для создания презентатора для тестов? Держу пари, что вы запускаете все в фоновой угрозе. Хотя это работает для приложения, это не будет для теста (который должен быть заблокирован)

2. Да, я пытался установить задержку в коде и в тесте, ничего не помогло

3. @Pelocho Я думаю, вы правы, но как это исправить?)

Ответ №1:

Проблема в том, что вы выполняете некоторые вычисления в фоновом потоке, и, даже будучи высмеянным, у него недостаточно времени для завершения до verify вызова

Поскольку вы уже вводите планировщики для своих операций, укажите, что они оба есть trampoline , поэтому все выполняется в одном потоке

 @Before
fun setUp() {
    presenter = CreateAccountPresenter(
        Schedulers.trampoline(),
        Schedulers.trampoline(),
        ...
    )
}
  

В худшем случае вы можете добавить какой-нибудь блокирующий элемент (например, Semaphore ), который блокирует выполнение теста, и вы освобождаете его одним из своих view методов (который вам нужно заглушить)

Согласно документам, Schedulers.trampoline() планирует все задачи в текущем потоке, поэтому все будет блокироваться. В случае, если вы хотите напрямую использовать некоторые планировщики, такие как Schedulers.io() , вам нужно переопределить их аналогично тому, что вы делаете сейчас с

 RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() } // Override MainThreadScheduler
  

Обратите внимание, что предыдущий фрагмент является всего лишь примером, и вам нужно будет его адаптировать

Комментарии:

1. Да, это работает, спасибо, но вы можете объяснить, почему? Что делают Schedulers.trampoline()?

2. И если я буду использовать just .subscribeOn(Schedulers.io ()) .observeOn(AndroidSchedulers.MainThread()) Это не сработает? И почему?

3. Поскольку вы уже использовали это в своем коде, я предположил, что вы знаете, что это такое и как это работает. Я добавлю некоторое объяснение в ответ

4. Это создал старый разработчик этого проекта, я могу использовать его, но я не знаю, почему он это сделал, вот почему я ответил

5. Я рекомендую вам ознакомиться с официальной документацией в reactivex.io . В противном случае вы столкнетесь с несколькими проблемами, которых можно легко избежать, не совершая глупых ошибок