我正在测试使用Architecture Components中的Room库生成的DAO类.我想检查加入多个表的查询返回的LiveData是否会在数据更改时更新.
我开始使用InOrder验证,但发现无论我想断言什么参数,Mockito会说该方法是用不同的方法调用的(当我将断言更改为那个时,它会说它是另一个) .
使用ArgumentCaptor结果可以正常工作,这是这个问题的主题:
为什么ArgumentCaptor验证在这里工作,但InOrder没有?
看看how to verify multiple method calls with different params的问题答案,两种方法都应该可以正常工作.
这是我的测试的简化版本,展示了这个问题:
package com.example
import com.nhaarman.mockito_kotlin.argumentCaptor
import com.nhaarman.mockito_kotlin.check
import com.nhaarman.mockito_kotlin.mock
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.*
import org.mockito.junit.MockitoJUnitRunner
@Suppress("IllegalIdentifier")
@RunWith(MockitoJUnitRunner::class)
class MultipleCallbacksVanillaTest {
private val java = Language("Java")
private val javascript = Language("JavaScript")
private val kotlin = Language("Kotlin")
private val firstList = emptyList<Language>()
private val secondList = listOf(java)
private val thirdList = listOf(java, javascript, kotlin)
private val lastList = listOf(java, kotlin)
@Test fun `using argument captor`() {
// given
val observer = mock<Observer<List<Language>>>()
val liveData = MutableLiveData<List<Language>>()
// when
liveData.observeForever(observer)
liveData.value = firstList
liveData.value = secondList
liveData.value = thirdList
liveData.value = lastList
// then
argumentCaptor<List<Language>>().run {
verify(observer, times(4)).onChanged(capture())
val (firstValue, secondValue, thirdValue, lastValue) = allValues
assertEquals(firstList, firstValue)
assertEquals(secondList, secondValue)
assertEquals(thirdList, thirdValue)
assertEquals(lastList, lastValue)
}
}
@Test fun `using in order`() {
// given
val observer = mock<Observer<List<Language>>>()
val liveData = MutableLiveData<List<Language>>()
// when
liveData.observeForever(observer)
liveData.value = firstList
liveData.value = secondList
liveData.value = thirdList
liveData.value = lastList
// then
inOrder(observer).run {
verify(observer).onChanged(check { assertEquals(firstList, it) })
verify(observer).onChanged(check { assertEquals(secondList, it) })
verify(observer).onChanged(check { assertEquals(thirdList, it) })
verify(observer).onChanged(check { assertEquals(lastList, it) })
}
verifyNoMoreInteractions(observer)
}
}
data class Language(val name: String)
interface Observer<in T> {
fun onChanged(value: T?)
}
class MutableLiveData<T : Any> {
var value: T
get() = _value
set(value) {
observers.forEach { it.onChanged(value) }
_value = value
}
private lateinit var _value: T
private var observers = mutableSetOf<Observer<T>>()
fun observeForever(observer: Observer<T>) {
if (::_value.isInitialized) observer.onChanged(_value)
observers.add(observer)
}
}
使用参数captor传递,但使用顺序失败并显示一条消息:
java.lang.AssertionError:
Expected :[]
Actual :[Language(name=Java)]
最佳答案 TL; DR – 就其检查功能而言,这似乎是
Mockito-Kotlin’s部分的错误和/或错误文档.
Mockito-Kotlin的wiki says:
If you want to do more assertions on the received argument, you can use
check
. […] If you want your test to fail inside acheck
invocation, you should make sure the body throws an error […]
检查calls Mockito’s argThat
的实现,并将提供的谓词作为参数传递.但是,the documentation for ArgumentMatcher
states:
The method should never assert if the argument doesn’t match. It should only return
false
.
因此,Mockito-Kotlin的文档与这种约束直接矛盾.
我不知道如何解决这个问题,但你现在可以完全避免检查,并直接使用argThat(适当时返回false,而不是抛出).