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

无法注入Mock Runnable至服务调用,Mockito验证重试次数失败

问题分析与解决方案

核心问题

你的测试代码存在两个关键错误,导致mock的Runnable从未被调用:

  1. 参数匹配不匹配:你在doAnswer中指定了固定参数"test"和mockRunnable,但实际ServiceA.getData()调用callRunnableWithRetry时,传入的是obj.getName()(值为"test-value")和一个匿名Runnable实例,和你mock的mockRunnable完全不是同一个对象,所以这个Stub逻辑根本没触发。
  2. Stub逻辑不符合实际代码流程:RetryService.callRunnableWithRetry的设计是返回装饰后的CheckedRunnable,由调用方(也就是ServiceA)去执行run()方法,但你的Stub直接在内部执行了checkedRunnable.run(),而没有返回这个装饰后的对象,和真实代码的执行流程不一致。

修正后的测试代码(直接追踪调用次数)

@Test
void testRetry(){
    RetryService retryServiceSpy = spy(retryService);
    ObjectA obj = new ObjectA("test-value");

    // 自定义带计数和异常逻辑的Runnable
    AtomicInteger callCount = new AtomicInteger(0);
    Runnable testRunnable = () -> {
        callCount.incrementAndGet();
        // 前两次调用抛异常,第三次正常执行
        if (callCount.get() <= 2) {
            throw new RuntimeException("Simulated exception");
        }
    };

    // 拦截callRunnableWithRetry,替换传入的Runnable为我们的测试实例
    doAnswer(invocation -> {
        String configName = invocation.getArgument(0);
        Retry retry = retryServiceSpy.getRetry(configName);
        // 装饰测试用Runnable并返回,保持原方法的返回逻辑
        return Retry.decorateCheckedRunnable(retry, testRunnable::run);
    }).when(retryServiceSpy).callRunnableWithRetry(eq(obj.getName()), any(Runnable.class));

    // 执行测试方法
    serviceA.getData(obj);

    // 验证总调用次数是否为3次
    assertThat(callCount.get()).isEqualTo(3);
}

可选方案:通过Retry事件验证重试逻辑

如果你不想修改Runnable的行为,也可以通过监听Resilience4j的Retry事件来确认重试是否触发:

@Test
void testRetry(){
    RetryService retryServiceSpy = spy(retryService);
    ObjectA obj = new ObjectA("test-value");

    AtomicInteger retryEventCount = new AtomicInteger(0);
    // 拦截Retry实例的创建,监听重试事件
    doAnswer(invocation -> {
        Retry retry = invocation.callRealMethod();
        // 每触发一次重试,计数器+1
        retry.getEventPublisher().onRetry(event -> retryEventCount.incrementAndGet());
        return retry;
    }).when(retryServiceSpy).getRetry(eq(obj.getName()));

    // 执行测试方法
    serviceA.getData(obj);

    // 验证重试次数是否为2次(总调用3次,重试2次)
    assertThat(retryEventCount.get()).isEqualTo(2);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 22:40:55