The following is the test code for my ViewModel
class. My app architecture is based on MVI. Basically, I'm trying to mock my repo and state classes. In the test function I wrote below, I'm trying to check if state is changed in correct order when I successfully load a news list from an API.
class NewsListViewModelTest {
//...
@get:Rule
val testSchedulerRule = RxTestSchedulerRule()
private lateinit var testSubject: NewsListViewModel
private val loadingState = NewsListState(state = State.LOADING)
private val newsRepo = mock<NewsRepository>()
private val observer = mock<Observer<NewsListState>>()
@Before
fun setUp() {
testSubject = NewsListViewModel(newsRepo)
testSubject.observableState.observeForever(observer)
}
@Test
fun `Given news list successfully loaded, when action LoadNewsList is received, then state contains news list`() {
// GIVEN
val newsList = listOf(News("title", "description", Date(), "image"))
val successState = NewsListState(newsList = newsList, state = State.DATA)
whenever(newsRepo.loadAll("keyword", 1, 1))
.thenReturn(Observable.just(newsList))
// WHEN
testSubject.dispatch(NewsListAction.LoadNewsList("keyword"))
testSchedulerRule.triggerActions()
// THEN
inOrder(observer) {
verify(observer).onChanged(loadingState)
verify(observer).onChanged(successState)
}
verifyNoMoreInteractions(observer)
}
}
However, when I run this test, I'm getting the following error in the first line inside inOrder(observer){ ... }
:
Wanted but not invoked:
observer.onChanged(
NewsListState(newsList=[], state=LOADING, errorMessage=)
);
-> at [packagename].NewsListViewModelTest.Given news list failed to load, when action LoadNewsList is received, then state contains error(NewsListViewModelTest.kt:77)
Actually, there were zero interactions with this mock.
And these are my testing dependencies:
testImplementation 'junit:junit:4.12'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0'
What might be the reason of this error?
Edit -- My RxTestSchedulerRule
class:
class RxTestSchedulerRule(private val testScheduler: TestScheduler = TestScheduler()) : Scheduler(),
TestRule {
override fun apply(base: Statement, description: Description?): Statement {
RxJavaPlugins.setIoSchedulerHandler { testScheduler }
RxJavaPlugins.setComputationSchedulerHandler { testScheduler }
RxJavaPlugins.setNewThreadSchedulerHandler { testScheduler }
RxJavaPlugins.setSingleSchedulerHandler { testScheduler }
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
return base
}
override fun createWorker() = testScheduler.createWorker()
fun triggerActions() = testScheduler.triggerActions()
}
Edit 2 -- My dispatch function:
fun dispatch(?) {
newsRepository.loadAll(keyword = it.keyword,
pageSize = pageSize,
page = page)
.subscribeOn(Schedulers.io())
.map<NewsListChange> { newsList ->
NewsListChange.Data(newsList) }
.defaultIfEmpty(NewsListChange.Data(emptyList()))
.onErrorReturn { throwable ->
NewsListChange.Error(throwable) }
.startWith(NewsListChange.Loading)
}
please try instead of this line
whenever(newsRepo.loadAll("keyword", 1, 1))
.thenReturn(Observable.just(newsList))
put
whenever(newsRepo.loadAll(anyString(), anyInt(), anyInt()))
.thenReturn(Observable.just(newsList))