Search code examples
androidunit-testingmockitorx-javarx-java2

Can`t get response from RxJava in Unit test


I tried to get response from RxJava2 in Unit test, I found an example how to do it, but i can`t see and response, can yoy help me? Thank you. The code itself has been working for a long time, without problems, and when the tests were required I encountered a problem, similar examples are more or less the same, but everywhere it is done this way, but it does not work for me.

There my code from 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()
                    }
            )
    )
}

And test:

@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()
}

But issue is:

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

Solution

  • The issue is that you're doing some computation in a background thread and, even being mocked, it doesn't have enough time to finish before the verify invocation

    Since you're already injecting the schedulers for your operations, specify that both of them are trampoline so everything runs in the same thread

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

    Worst case scenario, you can add some blocker element (such as a Semaphore) that blocks the test execution and you release it in one of your view methods (that you'll need to stub)

    As per the docs, Schedulers.trampoline() schedules all tasks in the current thread so everything will be blocking. In case you want to directly use some schedulers like Schedulers.io() you'll need to override them in a similar way you're doing now with

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

    Note that the previous snippet is just an example and you'll need to adapt it