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

JMockit迁移Mockito:枚举常量方法调用次数验证改造

枚举方法调用次数测试:从JMockit迁移至Mockito

需求背景

原有基于JMockit的测试用例,用于统计HyperlinkActionType枚举中performActionIfApplicable方法的调用次数,预期仅EDIT枚举常量会触发该方法,调用次数为1。由于Java17环境限制,需要将测试从JMockit迁移至Mockito,且需通过对每个枚举值进行spy的方式实现。


原枚举代码(HyperlinkActionType.java)

public enum HyperlinkActionType {
    EDIT("Edit") {
        @Override
        public void invokeRequest(String entityId) {
            performActionIfApplicable(entityId);
        }
    },

    DONOTHING("Donothing") {
        @Override
        public void invokeRequest(String entityId) {
            // 空实现
        }
    };

    public void invokeRequest(String entityId) {
        // 默认实现
    }

    void performActionIfApplicable(String entityId) {
        // 原有业务逻辑
    }
}

原JMockit测试代码

public void testActionsThatNeedVerifyingPermissionsBeforeExecution() {
    IntegerWrapper value = new IntegerWrapper(0);
    new MockUp<HyperlinkActionType>() {
        @SuppressWarnings("ParameterHidesMemberVariable")
        @Mock
        void performActionIfApplicable(String entityId) {
            value.increment();
        }
    };

    // 遍历所有枚举值并调用invokeRequest
    Arrays.stream(HyperlinkActionType.values()).forEach(action -> action.invokeRequest(null));

    Assert.assertEquals("仅EDIT操作应触发performActionIfApplicable方法",
            1, value.getWrappedObject().intValue());
}

迁移后的Mockito测试代码

import org.junit.Test;
import org.mockito.Mockito;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

public class HyperlinkActionTypeTest {

    @Test
    public void testActionsThatNeedVerifyingPermissionsBeforeExecution() {
        // 方式1:用Mockito原生verify验证调用次数(推荐)
        HyperlinkActionType[] spiedEnums = Arrays.stream(HyperlinkActionType.values())
                .map(Mockito::spy)
                .toArray(HyperlinkActionType[]::new);

        // 调用所有枚举实例的invokeRequest
        Arrays.stream(spiedEnums).forEach(action -> action.invokeRequest(null));

        // 逐个验证方法调用次数
        for (HyperlinkActionType spiedAction : spiedEnums) {
            if (spiedAction == HyperlinkActionType.EDIT) {
                verify(spiedAction, times(1)).performActionIfApplicable(Mockito.anyString());
            } else {
                verify(spiedAction, times(0)).performActionIfApplicable(Mockito.anyString());
            }
        }

        // 方式2:沿用原JMockit的计数器逻辑(和旧测试对齐)
        /*
        AtomicInteger callCount = new AtomicInteger(0);
        Arrays.stream(HyperlinkActionType.values())
                .map(Mockito::spy)
                .forEach(spiedAction -> {
                    // 拦截performActionIfApplicable方法并计数
                    Mockito.doAnswer(invocation -> {
                        callCount.incrementAndGet();
                        return null;
                    }).when(spiedAction).performActionIfApplicable(Mockito.anyString());
                    spiedAction.invokeRequest(null);
                });
        
        assertEquals("仅EDIT操作应触发目标方法", 1, callCount.get());
        */
    }
}

迁移关键说明

  • 枚举Spy的必要性:枚举实例是天然单例且不可变,Mockito无法直接mock整个枚举类,必须对每个枚举实例单独创建spy对象,保留原有业务逻辑的同时记录方法调用行为。
  • Java17适配:Mockito的spy方式无需修改枚举类结构,避开了JMockit在Java17模块化环境下的反射兼容性问题。
  • 两种验证逻辑:既可以用Mockito原生的verify方法直接验证调用次数,也可以沿用原测试的计数器逻辑,按需选择即可。

内容的提问来源于stack exchange,提问作者Margub Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:03:24