如何用Mockk创建接口实例时保留默认实现仅Mock抽象方法?
在Mockk中保留Kotlin接口默认方法并Mock抽象方法
当然可行!Mockk完全支持这种场景——你可以只mock接口中的抽象方法,同时保留带有默认实现的方法的原始逻辑。下面是具体的实现方式和示例代码:
1. 基础定义(你的接口和数据类)
首先回顾一下你的原始代码:
data class ItemData(val id: Int) interface Database { fun insertItems(items: List<ItemData>) fun deleteItems(items: List<ItemData>) fun runTransaction(alsoDelete: Boolean) { insertItems(listOf(ItemData(id = 1), ItemData(id = 2), ItemData(id = 3))) if (alsoDelete) deleteItems(listOf(ItemData(id = 4), ItemData(id = 5), ItemData(id = 6))) } }
2. Mockk实现代码
下面是如何创建符合需求的mock实例,并验证行为:
import io.mockk.every import io.mockk.mockk import io.mockk.verify fun testDatabaseMock() { // 创建Database接口的mock实例 val dbMock = mockk<Database>() // 关键:让runTransaction调用接口中的原始默认实现 every { dbMock.runTransaction(any()) } answers { callOriginal() } // Mock抽象方法insertItems,这里可以自定义行为(比如什么都不做,或者验证调用) every { dbMock.insertItems(any()) } returns Unit // Mock抽象方法deleteItems,同样自定义行为 every { dbMock.deleteItems(any()) } returns Unit // 调用保留了默认逻辑的runTransaction方法 dbMock.runTransaction(alsoDelete = true) // 验证insertItems是否按默认逻辑被正确调用 verify { dbMock.insertItems(listOf(ItemData(1), ItemData(2), ItemData(3))) } // 验证deleteItems是否在alsoDelete=true时被正确调用 verify { dbMock.deleteItems(listOf(ItemData(4), ItemData(5), ItemData(6))) } }
3. 关键知识点解释
answers { callOriginal() }:这是实现保留默认方法的核心。当你对某个方法使用这个语句时,Mockk会放弃生成的stub实现,转而调用接口中定义的原始默认逻辑。- 抽象方法必须Mock:由于抽象方法没有默认实现,如果你不对它们进行mock,调用时会抛出
MockKException(提示找不到方法的响应)。我们通过every { ... } returns ...为这些方法提供一个简单的stub实现(这里返回Unit),也可以根据需求设置更复杂的行为。 - 验证交互:使用
verify { ... }可以确认默认方法是否按预期调用了被mock的抽象方法,确保整个逻辑流程符合预期。
内容的提问来源于stack exchange,提问作者gesuwall
相关产品推荐
相关产品推荐

