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

SpringBoot中用Mockito做JUnit测试时@Retryable失效问题

解决SpringBoot中@Retryable结合Mockito重试失效问题

问题核心

你遇到的问题根源是Spring的@Retryable依赖AOP代理生效,当用@InjectMocks直接创建RetryService对象时,该对象并非Spring容器管理的代理实例,导致重试逻辑的AOP切面没有被织入,所以方法仅执行一次就抛出异常。

解决方案1:使用@MockBean替换容器中的Dao(推荐)

@MockBean是Spring Boot提供的注解,它会替换Spring容器内的RetryDao实例为Mock对象,此时RetryService依然是Spring管理的代理对象,AOP切面正常工作,重试逻辑就能生效。

修改后的测试类代码:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MainApplication.class)
@EnableRetry // 确保重试功能已启用,若主类未添加此注解,测试类需补充
public class RetryServiceTest {
    @MockBean
    RetryDao dao;

    @Autowired
    RetryService service; // 注入Spring管理的代理对象

    @Test
    public void getNumberTest() {
        try {
            CustomException ce = new CustomException("alphabet Error");
            // 模拟三次抛出异常,匹配重试3次的配置
            when(dao.getNumber(anyString())).thenThrow(ce).thenThrow(ce).thenThrow(ce);
            String response = service.retry("a");
            log.info("Response: {}", response);
        } catch (Exception e) {
            log.error("Error in Test");
        }
    }
}

解决方案2:手动为@InjectMocks对象生成代理

如果必须使用@InjectMocks,可以通过Spring的AOP工具手动为实例生成代理,让重试逻辑织入:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = MainApplication.class)
@EnableRetry
public class RetryServiceTest {
    @Mock
    RetryDao dao;

    RetryService service;

    @Autowired
    private ApplicationContext context;

    @Before
    public void setup() {
        service = new RetryService();
        MockitoAnnotations.openMocks(this); // 将Mock的Dao注入Service
        // 手动生成代理对象,让重试逻辑生效
        service = context.getBeanFactory().createProxy(service, RetryService.class, true);
    }

    @Test
    public void getNumberTest() {
        try {
            CustomException ce = new CustomException("alphabet Error");
            when(dao.getNumber(anyString())).thenThrow(ce).thenThrow(ce).thenThrow(ce);
            String response = service.retry("a");
            log.info("Response: {}", response);
        } catch (Exception e) {
            log.error("Error in Test");
        }
    }
}

原因补充说明

  • 不使用Mockito时,@Autowired注入的RetryService是Spring生成的AOP代理对象,代理类会拦截被@Retryable标记的方法,按照注解配置实现重试逻辑。
  • 使用@InjectMocks时,是Mockito直接实例化了RetryService对象,没有经过Spring的AOP代理处理,因此@Retryable的注解逻辑完全不生效,方法仅执行一次就抛出异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 04:50:18