简体   繁体   English

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

[英]How to mock android room withTransaction method with Mockk

I'm trying to make some unit tests for my business logic.我正在尝试为我的业务逻辑进行一些单元测试。 I have repository in which I save to room database (2.1.0-rc01) some data from response.我有存储库,我将响应中的一些数据保存到房间数据库(2.1.0-rc01)。 Data saving into different tables with different dao in single transaction.在单个事务中将数据保存到具有不同 dao 的不同表中。 Code is simplified:代码简化:

ItemRepository项目库

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)
    }
}

For unit test I'm using Mockk library.对于单元测试,我使用 Mockk 库。 How can I mock room withTransaction method?.如何使用Transaction方法模拟房间? withTransaction is declared as withTransaction 声明为

suspend fun <R> RoomDatabase.withTransaction(block: suspend () -> R): R

I'm trying to writing test我正在尝试编写测试

@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)
    }
}

You first have to enable static mocks for the Android Room KTX method withTransaction {} .您首先必须为 Android Room KTX 方法withTransaction {}启用静态模拟 You also need to capture the suspend lambda function passed to it.您还需要捕获传递给它的挂起 lambda 函数。 This captured function can just be invoked so the code inside it runs.这个捕获的函数可以被调用,这样它里面的代码就可以运行了。 Since you're mocking all the database calls, you don't need a real transaction here.由于您正在模拟所有数据库调用,因此这里不需要真正的事务。

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

  mockkStatic(
            "androidx.room.RoomDatabaseKt"
  )

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

You should then be able to run your code as written.然后,您应该能够按编写的方式运行代码。

To expand on Andrew's answer, the mockk documentation for extension functions shows that if you are mocking an object wide or class wide extension function, you can just use regular mockk to achieve that.为了扩展 Andrew 的回答,扩展函数mockk 文档显示,如果您正在模拟对象范围或类范围的扩展函数,则可以使用常规的mockk来实现这一点。 However, if you are using a module wide extension function, like withTransaction , you also need to perform mockkStatic on the module's class name.但是,如果您使用模块范围的扩展函数,例如withTransaction ,您还需要对模块的类名执行mockkStatic

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM