为什么在对 ViewModel 进行单元测试时会得到不同的结果?
我进行了两项测试。当我单独启动每个测试时,这没问题,但是当我连续启动所有测试时,我收到了错误。
这是一个 ViewModel,每次我从一个返回时都会改变状态
API。我希望 android.arch.lifecycle.Observer.onChanged
被调用两次,但第二次测试只调用一次。
当我将 verify(view, times(2)).onChanged(arg.capture())
替换为 verify(view, atLeastOnce()).onChanged(arg.capture) 时,单元测试工作正常())
在第一次测试时。
用户 View 模型:
class UserViewModel(
private val leApi: LeApi
): ViewModel() {
private val _states = MutableLiveData<ViewModelState>()
val states: LiveData<ViewModelState>
get() = _states
fun getCurrentUser() {
_states.value = LoadingState
leApi.getCurrentUser()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ user -> _states.value = UserConnected(user) },
{ t -> _states.value = FailedState(t) }
)
}
}
}
用户 View 模型测试:
@RunWith(MockitoJUnitRunner::class)
class UserViewModelTest {
lateinit var userViewModel: UserViewModel
@Mock
lateinit var view: Observer<ViewModelState>
@Mock
lateinit var leApi: LeApi
@get:Rule
val rule = InstantTaskExecutorRule()
@Before
fun setUp() {
RxAndroidPlugins.setInitMainThreadSchedulerHandler { Schedulers.trampoline() }
userViewModel = UserViewModel(leApi)
userViewModel.states.observeForever(view)
}
@Test
fun testGetCurrentUser() {
val user = Mockito.mock(User::class.java)
`when`(leApi.getCurrentUser()).thenReturn(Single.just(user))
userViewModel.getCurrentUser()
val arg = ArgumentCaptor.forClass(ViewModelState::class.java)
verify(view, times(2)).onChanged(arg.capture())
val values = arg.allValues
assertEquals(2, values.size)
assertEquals(LoadingState, values[0])
assertEquals(UserConnected(user), values[1])
}
@Test
fun testGetCurrentUserFailed() {
val error = Throwable("Got error")
`when`(leApi.getCurrentUser()).thenReturn(Single.error(error))
userViewModel.getCurrentUser()
val arg = ArgumentCaptor.forClass(ViewModelState::class.java)
verify(view, times(2)).onChanged(arg.capture()) // Error occurred here. That's the 70th line from stack trace.
val values = arg.allValues
assertEquals(2, values.size)
assertEquals(LoadingState, values[0])
assertEquals(FailedState(error), values[1])
}
}
预计: 所有测试均已通过。
实际:
org.mockito.exceptions.verification.TooLittleActualInvocations:
view.onChanged(<Capturing argument>);
Wanted 2 times:
-> at com.dev.titi.toto.mvvm.UserViewModelTest.testGetCurrentUserFailed(UserViewModelTest.kt:70)
But was 1 time:
-> at android.arch.lifecycle.LiveData.considerNotify(LiveData.java:109)
最佳答案
我遇到了这个问题。我将测试方式更改为以下( Google recommendations, here are the classes used for following test ):
将协程添加到您的项目中,因为测试助手使用它们:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1")
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.3.0'
去掉这一行:
lateinit var view: Observer<ViewModelState>
然后将您的测试更改为以下内容:
private val testDispatcher = TestCoroutineDispatcher()
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
...
}
@After
fun tearDown() {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
...
}
@Test
fun testGetCurrentUser() {
runBlocking {
val user = Mockito.mock(User::class.java)
`when`(leApi.getCurrentUser()).thenReturn(Single.just(user))
userViewModel.states.captureValues {
userViewModel.getCurrentUser()
assertSendsValues(100, LoadingState, UserConnected(user))
}
}
}
关于android - 单元测试: Observer onChanged should be called twice instead of once,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55874840/