我正在测试使用Room
中的Architecture Components
库生成的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)
}
}
using argument captor
次通过,但using in order
失败并显示一条消息:
java.lang.AssertionError:
Expected :[]
Actual :[Language(name=Java)]
答案 0 :(得分:1)
TL; DR - 就check
功能而言,这似乎是Mockito-Kotlin's部分的错误和/或错误文档。
Mockito-Kotlin&#39; wiki says:
如果要对收到的参数进行更多断言,可以使用
check
。 [...]如果您希望测试在check
调用内失败,则应确保正文引发错误[...]
check
calls Mockito's argThat
的实现,并将提供的谓词作为参数传递。但是,the documentation for ArgumentMatcher
states:
如果参数不匹配,该方法永远不应断言。它应该只返回
false
。
因此,Mockito-Kotlin的文件与这种约束直接矛盾。
我不确定如何解决此问题,但您现在可以完全避免使用check
,并直接使用argThat
(根据需要返回false
,而不是投掷)。
答案 1 :(得分:0)
使用check
(而不是Mockito-Kotlin提供的)功能似乎工作正常:
inline fun <reified T> check(noinline predicate: (T?) -> Unit): T? {
return Mockito.argThat {
try {
predicate(it)
true
} catch (e: Throwable) {
false
}
}
}
此问题已在2.0.0-alpha04版本的mockito-kotlin修复。