I am investigation the MockK library with my Android JUnit tests
testImplementation "io.mockk:mockk:1.10.0"
I have an issue when attempting to spyk on suspend functions
heres my Junit test
@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()
}
}
}
This test throws an java.lang.AssertionError at dao.reset()
as follows:-
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: -
My dao reset() method resembles this:-
@Transaction
suspend fun reset() {
delete()
insert(BackoffCriteriaDO(THE_BACKOFF_CRITERIA_ID, BACKOFF_CRITERIA_MILLISECOND_DELAY, BACKOFF_CRITERIA_MAX_RETRY_COUNT))
}
Why am I seeing this java.lang.AssertionError
?
How do I coVerify
that suspend functions have been called?
UPDATE
I believe the issue is caused by the fact I am using Room database.
My dao interface method reset()
is implemented by room generated code as
@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);
}
which means the coVerify{} is matching this function and not my interface version.
Is it possible to match this generated version of public Object reset(final Continuation<? super Unit> p0)
?
Is this a more basic issue with mockk that it cannot mockk java classes? Or Java implementations of Kotlin interfaces?
UPDATE 2
When my Room DAO functions are not suspend then Mockk works as required
using these dummy functions in my DAO:-
@Transaction
fun experimentation() {
experiment()
}
@Transaction
fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
My test passes
@Test
fun experimentation() = runBlocking {
val actual = myRoomDatabase.backoffCriteriaDAO()
val dao = spyk(actual)
dao.experimentation()
verify { dao.experiment() }
}
When I change my dummy functions as follows the test still passes
@Transaction
suspend fun experimentation() {
experiment()
}
@Transaction
fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
However when I change my dummy functions as follows the test throws an exception
@Transaction
suspend fun experimentation() {
experiment()
}
@Transaction
suspend fun experiment() {
experimental()
}
@Query("DELETE from backoff_criteria")
fun experimental()
The failing tests resembles this:-
@Test
fun experimentation() = runBlocking {
val actual = myRoomDatabase.backoffCriteriaDAO()
val dao = spyk(actual)
dao.experimentation()
coVerify { dao.experiment() }
}
The exception is
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: -