You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mockito中doReturn未代理反而调用真实方法的问题咨询

解决依赖Application上下文的组件单元测试问题

你的问题核心在于Mockito默认无法处理Kotlin的final方法/类,以及静态方法调用,导致mock失效并触发真实代码执行。下面一步步分析并给出解决方案:

错误原因拆解

  1. BoxStore未初始化异常:
    Kotlin中所有类和方法默认是final的,而Mockito核心库默认无法mock final方法。你mock了ItemHelper但stub未生效,导致调用了真实的retrieveItems方法,而测试环境中没有初始化BoxStore,因此抛出异常。

  2. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:48:06