如何使用Cucumber测试Spring Boot的@Retryable注解
Spring Boot @Retryable方法的Cucumber集成测试实现
一、基础准备
确保项目依赖包含Spring Retry、Cucumber、WireMock,同时在Spring Boot启动类上添加@EnableRetry注解开启重试功能。
二、WireMock场景配置
利用WireMock的Scenario功能模拟两种核心测试场景:
- 重试后成功:前两次返回500异常,第三次返回200
- 始终失败:三次请求均返回500
示例配置代码:
// 重试后成功的Stub stubFor(get(urlEqualTo("/target-api")) .inScenario("Retry Success Scenario") .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse().withStatus(500)) .willSetStateTo("First Attempt Failed")); stubFor(get(urlEqualTo("/target-api")) .inScenario("Retry Success Scenario") .whenScenarioStateIs("First Attempt Failed") .willReturn(aResponse().withStatus(500)) .willSetStateTo("Second Attempt Failed")); stubFor(get(urlEqualTo("/target-api")) .inScenario("Retry Success Scenario") .whenScenarioStateIs("Second Attempt Failed") .willReturn(aResponse().withStatus(200))); // 始终失败的Stub stubFor(get(urlEqualTo("/target-api")) .inScenario("Retry Fail Scenario") .whenScenarioStateIs(Scenario.STARTED) .willReturn(aResponse().withStatus(500)) .willSetStateTo("Failed")); stubFor(get(urlEqualTo("/target-api")) .inScenario("Retry Fail Scenario") .whenScenarioStateIs("Failed") .willReturn(aResponse().withStatus(500)));
三、重试次数统计的两种可行方案
方案1:基于Spring RetryListener统计
实现Spring Retry提供的RetryListener接口,监听重试过程统计重试次数(不含首次尝试):
@Component public class RetryCounterListener implements RetryListener { private int retryTimes = 0; @Override public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) { return true; } @Override public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) { retryTimes = context.getRetryCount(); } @Override public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {} public int getRetryTimes() { return retryTimes; } public void resetCounter() { retryTimes = 0; } }
测试时注入该Listener,调用方法后断言retryTimes等于2(对应maxAttempts=3,重试2次)。
方案2:Spring AOP统计总调用次数
通过AOP拦截所有标注@Retryable的方法,统计含首次尝试的总调用次数:
@Component @Aspect public class RetryMethodInterceptor { private int totalInvokeCount = 0; @Pointcut("@annotation(org.springframework.retry.annotation.Retryable)") public void retryableMethods() {} @Before("retryableMethods()") public void countInvocations(JoinPoint joinPoint) { totalInvokeCount++; } public int getTotalInvokeCount() { return totalInvokeCount; } public void resetCounter() { totalInvokeCount = 0; } }
maxAttempts=3时,总调用次数为3,直接断言该值即可。
四、Cucumber测试用例编写
场景1:重试后成功
Scenario: 服务调用失败后重试,最终成功 Given WireMock已配置为前两次返回500,第三次返回200 When 调用标注@Retryable的服务方法 Then 方法返回HTTP 200状态码 And 重试次数统计为2次(或总调用次数为3次)
场景2:始终失败
Scenario: 服务调用多次重试后仍失败 Given WireMock已配置为三次都返回500 When 调用标注@Retryable的服务方法 Then 方法抛出指定异常 And 重试次数统计为2次(或总调用次数为3次)
五、关键注意事项
- 每个测试用例执行前,必须重置统计计数器,避免用例间数据污染
- 由于设置了delay=1,测试时可借助Awaitility工具等待重试完成,避免断言时机过早
- WireMock的Scenario在每次测试后要调用
resetAllScenarios()重置状态
内容的提问来源于stack exchange,提问作者sejo
相关产品推荐
相关产品推荐

