Spek + Retrofit API тестовый сбой

Я пытаюсь протестировать Retrofit API с помощью Spek

Он генерирует исключение nullPointerException в блоке {...}

Связанная трассировка стека: https://pastebin.com/gy6dLtGg

Вот мой тестовый класс

@RunWith(JUnitPlatform::class)
class AccountCheckViewModelTest : Spek({

    include(RxSchedulersOverrideRule)

    val httpException = mock<HttpException> {
        on { code() }.thenReturn(400)
    }

    given(" account check view model") {
        var accountCheckRequest = mock<CheckExistingAccountRequest>()
        var accountCheckResponse = mock<CheckExistingAccountResponse>()
        var webService = mock<IAPICalls>()

        val accountCheckViewModel = spy(VMAccountCheck(webService))

        beforeEachTest {
            accountCheckRequest = mock<CheckExistingAccountRequest>() {
                on { email }.thenReturn("foo@mail")
            }

            accountCheckResponse = mock<CheckExistingAccountResponse>() {
                on { firstName }.thenReturn("foo")
                on { email }.thenReturn("foo@mail")
            }

            webService = mock<IAPICalls> {
                on { checkExistingAccount(accountCheckRequest) }.thenReturn(Flowable.just(accountCheckResponse))
            }
         }
        on("api success") {
            accountCheckViewModel.checkIfAccountExists(request = accountCheckRequest)

            it("should call live data with first name as foo") {
               verify(accountCheckViewModel, times(1)).updateLiveData(accountCheckResponse.firstName, accountCheckResponse.email, null)
            }
        }
    }
}

Вот мой класс RxSchedulersOverrideSpek

 class RxSchedulersOverrideSpek : Spek({

    beforeGroup {
        RxJavaPlugins.onIoScheduler(Schedulers.trampoline())
        RxJavaPlugins.onComputationScheduler(Schedulers.trampoline())
        RxJavaPlugins.onNewThreadScheduler(Schedulers.trampoline())
    }
})

2 ответа

Вы должны использовать memoized правильно настроить тестовые значения. Проблема в том, что accountCheckViewModel был инициализирован на этапе открытия Spek, webService макет, который был передан accountCheckViewModel было значение в тот момент (который вы не высмеивали ни одним из его методов). beforeEachTest запускается на этапе выполнения, вы переназначены webService здесь, чтобы правильно издеваться, но accountCheckViewModel по-прежнему содержит предыдущее значение.

given(" account check view model") {
  val accountCheckRequest by memoized {
    mock<CheckExistingAccountRequest>() {
      on { email }.thenReturn("foo@mail")
    }
  }
  val accountCheckResponse by memoized {
    mock<CheckExistingAccountResponse>() {
      on { firstName }.thenReturn("foo")
      on { email }.thenReturn("foo@mail")
    }
  }
  val webService by memoized {
    mock<IAPICalls> {
      on { checkExistingAccount(accountCheckRequest) }.thenReturn(Flowable.just(accountCheckResponse))
    }
  }

  val accountCheckViewModel by memoized {
    spy(VMAccountCheck(webService))
  }

  on("api success") {
    accountCheckViewModel.checkIfAccountExists(request = accountCheckRequest)

    it("should call live data with first name as foo") {
      verify(accountCheckViewModel, times(1)).updateLiveData(accountCheckResponse.firstName, accountCheckResponse.email, null)
    }
  }
}

Предполагая, что вы используете RxJava2 с RxAndroid, вы должны переопределить планировщик RxAndroid с помощью Schedulers.trampoline(), Таким образом, все задания, которые подписываются на trampoline(), ставятся в очередь и выполняются одна за другой в одном и том же потоке.

RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }

Ваш RxSchedulersOverrideSpek.kt должен выглядеть так:

object RxSchedulersOverrideSpek : Spek({

    beforeGroup {
        RxJavaPlugins.onIoScheduler(Schedulers.trampoline())
        RxJavaPlugins.onComputationScheduler(Schedulers.trampoline())
        RxJavaPlugins.onNewThreadScheduler(Schedulers.trampoline())
        RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
    }

    afterGroup {
        RxJavaPlugins.reset()
        RxAndroidPlugins.reset()
    }
})
Другие вопросы по тегам