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

Spring Retry最大重试次数JUnit测试用例编写问题求助

解决Spring Retry JUnit测试重试不生效的问题

你的测试没触发预期重试的核心原因很明确:Spring Retry的@Retryable注解是靠Spring AOP代理实现的,但你在测试里直接new MaxAttemptRetryService(),这个对象不是Spring容器管理的代理对象,所以注解的重试逻辑完全没被执行,自然sam()只被调用了1次。

给你两种可行的解决方案:

方案一:加载Spring上下文(推荐)

用@SpringBootTest让Spring管理bean,同时用@MockBean替换真实的Dao实现,这样就能拿到带AOP代理的服务对象,重试逻辑会正常生效:

@RunWith(SpringRunner.class)
// 加载需要的类到Spring上下文,也可以直接传入你的项目主启动类
@SpringBootTest(classes = {MaxAttemptRetryService.class, MaxAttemptDao.class})
public class HystrixServiceTest {

    @Autowired
    private MaxAttemptRetryService maxAttemptRetryService;

    // 用@MockBean替换容器里的真实MaxAttemptDao实例
    @MockBean
    private MaxAttemptDao maxAttemptDao;

    @Test(expected = Exception.class)
    public void testRetryMaxAttempts() throws Exception {
        // 配置Mock每次调用都抛出异常
        when(maxAttemptDao.sam()).thenThrow(new Exception("REST服务不可用"));

        try {
            maxAttemptRetryService.retry("ll");
        } finally {
            // 验证总共调用了3次(1次初始调用 + 2次重试)
            verify(maxAttemptDao, times(3)).sam();
        }
    }
}

方案二:手动创建代理(适合不想加载完整上下文的场景)

如果不想加载Spring上下文,可以手动用Spring的ProxyFactory创建带重试增强的代理对象,不过这种方式相对繁琐:

@RunWith(SpringRunner.class)
public class HystrixServiceTest {

    private MaxAttemptRetryService maxAttemptRetryService;

    @Mock
    private MaxAttemptDao maxAttemptDao;

    @Before
    public void setUp() {
        // 创建原始服务对象并注入Mock的Dao
        MaxAttemptRetryService target = new MaxAttemptRetryService();
        ReflectionTestUtils.setField(target, "maxAttemptDao", maxAttemptDao);

        // 手动创建代理,添加重试增强逻辑
        ProxyFactory proxyFactory = new ProxyFactory(target);
        proxyFactory.addAdvisor(new RetryAttributeSourceAdvisor(new AnnotationAwareRetryOperationsInterceptor()));
        maxAttemptRetryService = (MaxAttemptRetryService) proxyFactory.getProxy();
    }

    @Test(expected = Exception.class)
    public void testRetryMaxAttempts() throws Exception {
        when(maxAttemptDao.sam()).thenThrow(Exception.class);

        try {
            maxAttemptRetryService.retry("ll");
        } finally {
            verify(maxAttemptDao, times(3)).sam();
        }
    }
}

额外注意事项

  • 确保你的@EnableRetry注解生效(你的服务类已经添加,这点没问题);
  • 重试3次后,方法会抛出最终的异常,所以测试里要么用@expected声明预期异常,要么在try块里捕获,否则测试会因为未处理异常失败;
  • 不要用@InjectMocks直接new对象,这种方式绕过了Spring的AOP代理机制,注解逻辑无法触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:23:12