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

Mockito如何验证特定枚举实例上的方法被正确调用

根因说明

Java枚举是JVM类加载阶段初始化的全局单例final类型,默认Mockito配置下,直接创建枚举spy、或是全量mock枚举类,都无法替换业务代码实际引用的原始枚举实例,自然无法拦截方法调用、完成verify校验。

实现方案

需要使用Mockito inline mock maker(支持静态方法、final类型mock),操作步骤:

  • 开启inline mock能力:
    • 方案1:直接引入mockito-inline依赖(Mockito 3.4及以上版本内置支持)
    • 方案2:在测试资源路径创建src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker文件,文件内容写入mock-maker-inline
  • 测试逻辑中通过mockStatic拦截枚举实例的获取,将目标枚举实例替换为spy对象,存根paint方法跳过真实实现,最后完成调用校验。

测试代码示例(JUnit 5)

import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import static org.mockito.Mockito.*;

public class ColorsPaintTest {
    @Test
    void verifyRedPaintInvokeWithExpectedCar() {
        Car testCar = mock(Car.class);
        // 用try-with-resources管控静态mock生命周期,避免上下文污染其他用例
        try (MockedStatic<Colors> colorsStaticMock = mockStatic(Colors.class)) {
            // 为RED实例创建spy,存根paint方法不执行真实逻辑
            Colors redSpy = spy(Colors.RED);
            doNothing().when(redSpy).paint(any(Car.class));
            // 拦截Colors.RED的返回,替换为spy实例
            colorsStaticMock.when(() -> Colors.RED).thenReturn(redSpy);

            // 此处执行被测业务代码,例如逻辑中包含Colors.RED.paint(car)调用
            // demo: yourBusinessComponent.paintCarRed(testCar);

            // 校验:RED的paint方法被调用1次,入参为指定的testCar
            verify(redSpy, times(1)).paint(testCar);
        }
    }
}
注意事项
  • 必须手动关闭MockedStatic实例:JUnit5用try-with-resources自动回收,JUnit4需要在@After方法中手动close,否则静态mock上下文会泄漏,干扰其他测试用例执行。
  • 存根顺序不能乱:先完成spy对象的方法存根,再设置Colors.RED返回spy实例,避免业务逻辑提前拿到原始枚举实例导致拦截失效。
  • 如果业务代码可重构,更优实践是将颜色能力抽象为普通接口,枚举实现该接口,业务层通过依赖注入传入颜色实例,后续测试直接使用普通mock即可,无需依赖静态mock能力。

内容的提问来源于stack exchange,提问作者Andreas Dolk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:36:22