如何使用 Mockk 模拟 android 房间 withTransaction 方法

vvg*_*vvg 2 android kotlin android-room mockk kotlin-coroutines

我正在尝试为我的业务逻辑进行一些单元测试。我有存储库,我将响应中的一些数据保存到房间数据库(2.1.0-rc01)。在单个事务中将数据保存到具有不同 dao 的不同表中。代码简化:

项目库

suspend fun saveItems(response: Response) {
    val items = response.items.map { it.toLocalItem() }
    val subItems = response.items.flatMap { item ->
            item.subItems.map { it.toLocal(item.id) }
        }

    db.withTransaction {
        db.itemDao().deleteAll()
        db.itemDao().insertAll(items)
        db.subItemDao().insertAll(subItems)
    }
}
Run Code Online (Sandbox Code Playgroud)

对于单元测试,我使用 Mockk 库。如何使用Transaction方法模拟房间?withTransaction 声明为

suspend fun <R> RoomDatabase.withTransaction(block: suspend () -> R): R
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写测试

@MockK
private lateinit var database: AppDatabase
@MockK
private lateinit var itemDao: ItemDao
@MockK
private lateinit var subItemDao: SubItemDao


@Test
fun checkSaveItems() = runBlocking {
    repository = ItemRepository(database)
    coEvery { database.itemDao() } returns itemDao
    coEvery { database.subItemDao() } returns subItemDao

    //TODO: execute database.withTransaction(block: suspend () -> R)

    coEvery { itemDao.deleteAll() } just Runs
    coEvery { itemDao.insertAll(any()) } just Runs
    coEvery { subItemDao.insertAll(any()) } just Runs

    repository.saveItems(testResponse)

    coVerifySequence {
        itemDao.deleteAll()
        itemDao.insertAll(testItems)
        subItemDao.insertAll(testSubItems)
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*erg 6

您首先必须为 Android Room KTX 方法withTransaction {}启用静态模拟。您还需要捕获传递给它的挂起 lambda 函数。这个捕获的函数可以被调用,这样它里面的代码就会运行。由于您正在模拟所有数据库调用,因此这里不需要真正的事务。

@Before
fun initMocks() {
  MockKAnnotations.init(this)

  mockkStatic(
            "androidx.room.RoomDatabaseKt"
  )

  val transactionLambda = slot<suspend () -> R>()
    coEvery { db.withTransaction(capture(transactionLambda)) } coAnswers {
      transactionLambda.captured.invoke()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您应该能够按照编写的方式运行代码。

  • 谢谢,我尝试捕获但测试在没有静态模拟的情况下挂起 (2认同)
  • 必须将 -&gt; R 更改为 -&gt; Unit 才能让它为我工作 (2认同)