【发布时间】:2020-08-01 11:27:50
【问题描述】:
我正在使用我的 Android JUnit 测试调查 MockK 库
testImplementation "io.mockk:mockk:1.10.0"
我在尝试监视挂起函数时遇到问题
这是我的 Junit 测试
@ExperimentalCoroutinesApi
@FlowPreview
@RunWith(AndroidJUnit4::class)
class BackOffCriteriaDaoTest : BaseTest() {
@Rule
@JvmField
val instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var dao: BackoffCriteriaDAO
@Test
fun backOffCriteria() = runBlocking {
dao = spyk(myRoomDatabase.backoffCriteriaDAO())
assertNotNull(dao.getBackoffCriteria())
assertEquals(backOffCriteriaDO, dao.getBackoffCriteria())
dao.delete()
coVerify {
myRoomDatabase.backoffCriteriaDAO()
dao.reset()
}
}
}
这个测试在dao.reset() 抛出一个java.lang.AssertionError 如下:-
java.lang.AssertionError: Verification failed: call 2 of 2: BackoffCriteriaDAO_Impl(#2).reset(eq(continuation {}))). Only one matching call to BackoffCriteriaDAO_Impl(#2)/reset(Continuation) happened, but arguments are not matching:
[0]: argument: continuation {}, matcher: eq(continuation {}), result: -
我的 dao reset() 方法类似于:-
@Transaction
suspend fun reset() {
delete()
insert(BackoffCriteriaDO(THE_BACKOFF_CRITERIA_ID, BACKOFF_CRITERIA_MILLISECOND_DELAY, BACKOFF_CRITERIA_MAX_RETRY_COUNT))
}
为什么我会看到这个java.lang.AssertionError?
我如何coVerify 已调用挂起函数?
更新
我相信这个问题是由于我使用的是 Room 数据库造成的。
我的dao接口方法reset()是通过房间生成代码实现的
@Override
public Object reset(final Continuation<? super Unit> p0) {
return RoomDatabaseKt.withTransaction(__db, new Function1<Continuation<? super Unit>, Object>() {
@Override
public Object invoke(Continuation<? super Unit> __cont) {
return BackoffCriteriaDAO.DefaultImpls.reset(BackoffCriteriaDAO_Impl.this, __cont);
}
}, p0);
}
这意味着 coVerify{} 匹配的是这个函数,而不是我的接口版本。
是否可以匹配这个生成的public Object reset(final Continuation<? super Unit> p0) 版本?
这是一个更基本的 mockk 问题,它不能模拟 java 类吗? 还是 Kotlin 接口的 Java 实现?
更新 2
当我的 Room DAO 功能未暂停时,Mockk 将按要求工作
在我的 DAO 中使用这些虚拟函数:-
@Transaction
fun experimentation() {
experiment()
}
@Transaction
fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
我的测试通过了
@Test
fun experimentation() = runBlocking {
val actual = myRoomDatabase.backoffCriteriaDAO()
val dao = spyk(actual)
dao.experimentation()
verify { dao.experiment() }
}
当我如下更改我的虚拟函数时,测试仍然通过
@Transaction
suspend fun experimentation() {
experiment()
}
@Transaction
fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
但是,当我如下更改我的虚拟函数时,测试会引发异常
@Transaction
suspend fun experimentation() {
experiment()
}
@Transaction
suspend fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
失败的测试类似于:-
@Test
fun experimentation() = runBlocking {
val actual = myRoomDatabase.backoffCriteriaDAO()
val dao = spyk(actual)
dao.experimentation()
coVerify { dao.experiment() }
}
例外是
java.lang.AssertionError: Verification failed: call 1 of 1: BackoffCriteriaDAO_Impl(#2).experiment(eq(continuation {}))). Only one matching call to BackoffCriteriaDAO_Impl(#2)/experiment(Continuation) happened, but arguments are not matching:
[0]: argument: continuation {}, matcher: eq(continuation {}), result: -
【问题讨论】:
-
只是一个想法,您在验证之前致电
dao.delete()。但是,您正在验证的方法dao.reset()在其体内也有insert(...)。从错误来看,在我看来,insert(...)从未被调用,因此您的coVerify失败。 -
感谢您查看我的问题。我相信我的问题(来自 AssertionError)是因为我的 reset() 函数是一个挂起函数,所以添加了一个延续函数 arg,这意味着它与我放置在 coVerify{} 块中的 no Args 方法不匹配。是否可以使用 mockk/spyk 匹配挂起函数?
标签: android android-room junit4 mockk