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
相关产品推荐
相关产品推荐

