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

使用Mockito mock final类内部方法时sCode返回null如何解决

问题背景

现有业务代码定义如下:

public final class PolicySummaryUtils {
   public PolicySummaryResponse.Policy getPolicy() {
       return getPolicySummaryResponse().accounts.get(0).policies.get(0);
   }
}

public static class Policy {
    @Expose
    public String sCode;
    @SerializedName("policySource")
    // 其余类成员省略
}

单元测试场景:需要在ViewModelTest中mock stateCode字段,已对policy对象做mock处理,但实际运行时sCode始终返回null,测试代码如下:

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class ViewModelTest{

    @Mock
    lateinit var summaryUtils: PolicySummaryUtils

    @Mock
    lateinit var policy: Policy

    @Test
    fun payBill_return_acceptedPayBillResponse(){
        return runTest {
            Mockito.when(summaryUtils.policyNumber).thenReturn(MOCK_POLICY_NO)
            Mockito.when(summaryUtils.policy).thenReturn(policy)
            Mockito.when(policy.stateCode).thenReturn(MOCK_STATE_CODE)
        }
    }
}

核心疑问:

  • 该场景下是否可以成功mock final类内部的方法?
  • 当前sCode返回null的问题该如何修复?

问题解答

final类方法Mock可行性

原生Mockito默认不支持mock final类、final方法,满足以下任一条件即可正常mock:

  • 使用Mockito 2及以上版本,在测试资源目录src/test/resources/mockito-extensions/下新建org.mockito.plugins.MockMaker文件,文件内容填写mock-maker-inline,开启inline mock maker能力
  • 使用Mockito 4及以上版本,部分发行版已默认开启final类mock支持
  • 引入PowerMock等扩展测试框架实现final类mock
    从当前代码能正常编写summaryUtils.policy的mock逻辑来看,final类mock的配置本身是生效的,这不是sCode返回null的根因。

sCode返回null的根因与修复

根因

问题出在两个编码错误:

  • 字段/属性名不匹配:定义的Policy类中公开字段名为sCode,测试代码中mock的是stateCode属性,Kotlin会将属性访问映射为对应getter方法调用,类中不存在getStateCode()方法时,mock逻辑根本不会绑定到目标字段上。
  • 错误mock公开字段:Mockito的when().thenReturn()逻辑针对的是方法调用拦截,Java的public字段是直接内存访问,不存在代理拦截点,mock生成的代理对象中所有字段默认都是类型初始值,引用类型固定为null,直接对字段做mock不会生效。

修复方案

最优实现是不要mock简单值对象,直接实例化真实Policy对象赋值即可,参考代码如下:

@ExperimentalCoroutinesApi
@RunWith(MockitoJUnitRunner::class)
class ViewModelTest{
    private val MOCK_POLICY_NO = "TEST_POLICY_001"
    private val MOCK_STATE_CODE = "TEST_STATE_001"

    @Mock
    lateinit var summaryUtils: PolicySummaryUtils

    private lateinit var policy: Policy

    @Before
    fun initTestData() {
        policy = Policy()
        // public字段直接赋值即可,不需要走mock逻辑
        policy.sCode = MOCK_STATE_CODE
    }

    @Test
    fun payBill_return_acceptedPayBillResponse() = runTest {
        // Kotlin中调用Java getter方法时需要加反引号避免和关键字冲突
        Mockito.`when`(summaryUtils.policyNumber).thenReturn(MOCK_POLICY_NO)
        Mockito.`when`(summaryUtils.policy).thenReturn(policy)
        // 编写后续测试断言逻辑
    }
}

补充说明:如果Policy类实际存在getStateCode()方法、sCode只是序列化对应的字段名,需要检查对应getter方法是否被final修饰、字段访问权限是否正确,确保Mockito能拦截到getter调用,这种场景下才可以使用Mockito.when(policy.stateCode).thenReturn(MOCK_STATE_CODE)的写法。


内容的提问来源于stack exchange,提问作者Abraham Mathew

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 19:18:26