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