我正在尝试使用 RetryConfig 实施测试。虽然我说应该重试哪个异常,但什么也没有发生。错误被抛出,测试完成。回退方法也不会被触发。我的测试有什么问题吗?
TestConfig.java
@TestConfiguration
public class TestRetryConfig {
@Autowired
private RetryRegistry retryRegistry;
@Bean("FeignRetry")
public Retry retryWithCustomConfig() {
RetryConfig customConfig = RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofSeconds(1))
.retryExceptions(FeignException.class)
.build();
return retryRegistry.retry("feignException", customConfig);
}
}
TestClass.java
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {MyAdapter.class, InMemoryRetryRegistry.class, ServerInternalErrorVerifier.class, TestRetryConfig.class})
class MyAdapterRetryTest {
@Autowired
private RetryRegistry registry;
@Autowired
private MyAdapter myAdapter;
@Autowired
private Retry retry; //i see here, that my retry has been injected correctly with defined bean-name
@MockBean
private MyClient myClient;
@Test
Request feignRequest =
Request.create(Request.HttpMethod.POST, "", Map.of(), "".getBytes(StandardCharsets.UTF_8), null, null);
FeignException.InternalServerError feignException =
new FeignException.InternalServerError("", feignRequest, "".getBytes(StandardCharsets.UTF_8), null);
when(myClient.sendPerson(any())).thenThrow(feignException); //here should retry be trigered
String result = myAdapter.sendPerson(myRequest);
assertThat(result).contains("was not send successfully");
}
}
我的产品方法
@Retry(name = "throwingFeignException", fallbackMethod = "logCommunicationFailure")
public String sendPartner(MyRequest myRequest) {
MyResponse response = myClient.sendPerson(myRequest);
return "ok";
}
private String logCommunicationFailure(MyRequest myRequest, Exception exception) {
return "fail";
}
TL;博士:
简短的答案是:您需要使用
Retry.decorateFunction()
对象和您提供的“My Prod-Method”代码片段中的 Retry retry
方法调用 sendPartner()
(存在不一致,因为您指的是 sendPerson()
在你的测试中——我认为你引用了相同的方法,这只是一个拼写错误。
assertThrows(
FeignException.InternalServerError.class,
() -> Retry.decorateFunction(retry, feignService::sendPartner).apply(person));
verify(myClient, times(3)).sendPerson(any(Person.class));
这将执行用
sendPartner()
装饰的 @Retry
方法,并验证它是否按照您的配置重试了 3 次。
FeignRetry配置Bean
@Configuration
public class FeignRetryConfiguration {
@Bean
MyClient myClient() {
return Feign.builder()
.client(new Client.Default(null, null))
.encoder(new Encoder.Default())
.decoder(new Decoder.Default())
.target(MyClient.class, "http://localhost:8080");
}
@Bean
RetryConfig feignRetryConfig() {
return RetryConfig.custom()
.maxAttempts(3)
.waitDuration(Duration.ofSeconds(1))
.retryExceptions(FeignException.InternalServerError.class)
.build();
}
@Bean("feignRetry")
RetryRegistry retryRegistry() {
return RetryRegistry.of(feignRetryConfig());
}
@Bean
Retry retryFeign(@Autowired @Qualifier("feignRetry") RetryRegistry retryRegistry) {
return retryRegistry.retry("throwingFeignException");
}
}
FeignService Bean
@Service
public class FeignService {
MyClient myClient;
public FeignService(MyClient myClient) {
this.myClient = myClient;
}
@Retry(name = "throwingFeignException", fallbackMethod = "logCommunicationFailure")
public String sendPartner(Person person) {
myClient.sendPerson(person);
return "ok";
}
public String logCommunicationFailure(Person person, Exception exception) {
return "fail";
}
}
我的客户端
public interface MyClient {
@RequestLine("POST")
@Headers("Content-Type: application/json")
void sendPerson(Person person);
}
人是 POJO - 为简洁起见,跳过
实际的单元测试
@SpringBootTest
class MyClientTest {
@TestConfiguration
static class MyClientTestConfiguration {
@Bean
FeignService feignService(@Autowired MyClient myClient) {
return new FeignService(myClient);
}
}
@MockBean
MyClient myClient;
@Autowired
@Qualifier("retryFeign")
Retry retry;
@Autowired
FeignService feignService;
@Test
void testSendPartnerShouldRetry() {
Request request = Request.create(Request.HttpMethod.POST, "", Collections.emptyMap(), "".getBytes(StandardCharsets.UTF_8), null);
doThrow(new FeignException.InternalServerError("internal error", request, "".getBytes(StandardCharsets.UTF_8), Collections.emptyMap()))
.when(myClient).sendPerson(any(Person.class));
Person person = new Person();
person.setName("John Doe");
person.setEmail("[email protected]");
person.setPhone("123456789");
assertThrows(FeignException.InternalServerError.class, () -> Retry.decorateFunction(retry, feignService::sendPartner).apply(person));
verify(myClient, times(3)).sendPerson(any(Person.class));
}
}
当然,您需要扩展此代码以使其按预期工作,但希望它能够演示如何实现它。