Mockito中doReturn未代理反而调用真实方法的问题咨询
解决依赖Application上下文的组件单元测试问题
你的问题核心在于Mockito默认无法处理Kotlin的final方法/类,以及静态方法调用,导致mock失效并触发真实代码执行。下面一步步分析并给出解决方案:
错误原因拆解
BoxStore未初始化异常:
Kotlin中所有类和方法默认是final的,而Mockito核心库默认无法mock final方法。你mock了ItemHelper但stub未生效,导致调用了真实的retrieveItems方法,而测试环境中没有初始化BoxStore,因此抛出异常。Unfinished Stubbing异常:
当Mockito尝试处理final方法时,内部逻辑出现错误,导致stub过程未完成,进而抛出该错误。
解决方案
方案1:修改ItemHelper方法为可mock(简单直接)
Kotlin方法默认final,我们需要显式标记为open让Mockito可以mock:
// ItemHelper.kt open fun retrieveItems(): MutableList<Item> { val boxStore = BoxStore.getInstance().getBoxFor(Item::class.java) return boxStore.all }
然后修正测试代码,确保stub写法正确:
@RunWith(MockitoJUnitRunner::class) class ItemHelperTests { @Mock private lateinit var itemHelper: ItemHelper @Test fun itemsNumber_Test() { // 使用doReturn避免调用真实方法 doReturn(ArrayList<Item>()).`when`(itemHelper).retrieveItems() // 调用方法并验证结果 val items = itemHelper.retrieveItems() assert(items.isEmpty()) } }
如果不想修改原代码,可以启用Mockito的inline扩展(支持mock final方法/类),在Module级别的build.gradle添加依赖:
testImplementation "org.mockito:mockito-inline:4.8.1" // 版本与你的mockito-core保持一致
方案2:mock依赖的BoxStore(更优雅的测试方式)
直接mockItemHelper虽然能解决问题,但更符合测试原则的做法是mock它依赖的BoxStore,避免修改原代码:
@RunWith(MockitoJUnitRunner::class) class ItemHelperTests { @Mock private lateinit var mockBoxStore: BoxStore @Mock private lateinit var mockBox: Box<Item> @Test fun itemsNumber_Test() { // mock静态方法BoxStore.getInstance(),返回我们的mock实例 Mockito.mockStatic(BoxStore::class.java).use { mockedStatic -> mockedStatic.`when`<BoxStore> { BoxStore.getInstance() }.thenReturn(mockBoxStore) // mock BoxStore的getBoxFor方法 `when`(mockBoxStore.getBoxFor(Item::class.java)).thenReturn(mockBox) // mock Box的all方法返回空列表 `when`(mockBox.all).thenReturn(ArrayList<Item>()) // 使用真实的ItemHelper实例测试 val itemHelper = ItemHelper() val items = itemHelper.retrieveItems() // 验证结果 assert(items.isEmpty()) // 可选:验证方法调用次数 mockedStatic.verify { BoxStore.getInstance() } verify(mockBoxStore).getBoxFor(Item::class.java) verify(mockBox).all } } }
注意事项:
- Mock静态方法需要依赖
mockito-inline库(同方案1的依赖) mockStatic必须在use块中使用,确保静态mock在测试结束后自动重置,避免影响其他测试用例
内容的提问来源于stack exchange,提问作者Rafael Ruiz Muñoz
相关产品推荐
相关产品推荐

