ursus
01/03/2020, 7:15 AMstreetsofboston
01/03/2020, 12:14 PMdelay
calls (be sure to use the version that takes a scheduler
).
Then call testScheduler.advanceTimeBy/To to advance (virtual) time, last the mock-delays, mimicking Loading state.ursus
01/03/2020, 1:53 PMursus
01/04/2020, 2:07 AMursus
01/04/2020, 2:07 AMursus
01/04/2020, 2:07 AMursus
01/04/2020, 2:09 AMval viewModel = createViewModel()
val testObserver = viewModel.stateObservable.test()
viewModel.init()
testObserver.assertValues(...)
Kashif
01/04/2020, 8:40 AMKashif
01/04/2020, 8:40 AMKashif
01/04/2020, 8:42 AMKashif
01/04/2020, 8:46 AMKashif
01/04/2020, 8:51 AMval orderInfoList by lazy {
val liveData = MutableLiveData<OrderListResult>()
loadingState.value = LoadingState.LOADING
val params = GetOrderInfoUseCase.Parameters(STATUS)
getOrderListUseCase.execute(object : FlowableSubscriber<Result<List<OrderInfo>>>() {
override fun onNext(t: Result<List<OrderInfo>>?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
loadingState.value = LoadingState.STOP_LOADING
}
override fun onError(t: Throwable?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
loadingState.value = LoadingState.STOP_LOADING
}
}, params)
addDisposable(getOrderListUseCase)
return@lazy liveData
}
}
override fun error(error: RetrofitError) {
logger.e(TAG, "get order list error occurred", error.errorMessage)
if (error.isNetworkError()) {
orderInfoList.value = OrderListResult.Error(resourceProvider.getString(R.string.network_unavailable))
} else {
orderInfoList.value = OrderListResult.Error(error.errorMessage)
}
checkAndGetInProgressOrders()
}
}, params)
addDisposable(getOrderListUseCase)
return@lazy liveData
}
ursus
01/04/2020, 2:53 PMKashif
01/04/2020, 5:17 PMDaniel
01/05/2020, 7:03 PM@Test
fun `Should reset the color of the info button when showing a valid info`() {
// GIVEN
val observer: (Int) -> Unit = mock()
viewModel.colorInfoButton.observeForever(
Observer(observer))
// WHEN
gameCommands.emit(ShowInfo(validInfo()))
// THEN
verify(observer).invoke(WHITE)
}
Don't forget
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
though, otherwise the test case crashesursus
01/06/2020, 12:55 PMursus
01/06/2020, 12:55 PMDaniel
01/06/2020, 12:59 PMassertThat(viewModel.liveData.value).isEqualTo(expectedValue)
Only sensible if you use multiple live data tough. If you use only one and push events to the view like this you can only assert the last one send 😕Kashif
01/06/2020, 1:02 PMstreetsofboston
01/06/2020, 1:19 PMLiveData
are like BehaviorSubjects (Rx). They are statefull. You can start your "command" in the constructor/init of your ViewModel (which happens during an onCreate) and attach/observe a bit later.
If the "command" finishes very quickly, the value from the LiveData will be emitted to the observer immediately as soon as the oberver subscribes/attaches.
If the "command" finishes later, the oberver attaches and as soon as the command finishes at a later time, the result is emitted to the observer.ursus
01/06/2020, 2:13 PMursus
01/06/2020, 2:13 PMursus
01/06/2020, 2:14 PMursus
01/06/2020, 2:14 PMursus
01/06/2020, 2:15 PMursus
01/06/2020, 2:15 PMursus
01/06/2020, 2:17 PM@Test fun `after view model init() called, await these refresh Signal values`() {
whenever(messageManager.refresh()).thenReturn(Observable.just(Foo(77)))
val initialState = InviteViewModel.State(refresh = Uninitialized)
val viewModel = createInviteViewModel(initialState)
val testSubscriber = viewModel.stateObservable.map { it.refresh }.test()
viewModel.init()
testSubscriber.awaitAndAssertValues(
Uninitialized,
Loading,
Success(Foo(77))
)
}
ursus
01/06/2020, 2:18 PMursus
01/06/2020, 2:18 PM@Test fun `meh asd`() {
val initialState = InviteViewModel.State(title = "")
val viewModel = createInviteViewModel(initialState)
val testSubscriber = viewModel.stateObservable.map { it.title }.test()
viewModel.changeTitle()
testSubscriber.awaitAndAssertValues(
"",
"Foo"
)
}
ursus
01/06/2020, 2:18 PMstreetsofboston
01/06/2020, 9:52 PMSuccess
emitted even before the constructor has finished?
Your view-model’s constructor could take an initial state (e.g Loading, since that would be the first thing the user sees) and a data-repository.
The view-model sets its state to the initial state and you could assert that that state is Loading.
whenever(repo.getTitle()).thenReturn(Single.just("New Title"))
viewModel = MyViewModel(repo, State.Loading)
val testSub = viewModel.stateObs.test()
testSub.assertValue(State.Loading)
viewModel.changeTitle() // will call repo.getTitle() which returns a Single<String>
testSub.assertValues(State.Loading, State.Success("New Title")) // or something similar
streetsofboston
01/06/2020, 9:54 PMwhenever(repo.getTitle()).thenReturn(Single.just("New Title").delay(1, TimeUnit.SECONDS, testScheduler))
viewModel = MyViewModel(repo, State.Loading)
val testSub = viewModel.stateObs.test()
testSub.assertValue(State.Loading)
testScheduler.advanceTimeBy(1, TimeUnit.SECONDS)
testSub.assertValues(State.Loading, State.Success("New Title")) // or something similar
ursus
01/07/2020, 6:17 AM