使用@RestClientTest时请求未被检测,如何测试异步RestClient服务?
问题:使用@RestClientTest测试RestClient调用时,MockRestServiceServer未检测到请求
我有一个通过默认配置的RestClient调用第三方API的服务,当使用@RestClientTest进行测试时,MockRestServiceServer未检测到任何传入请求,不确定是RestClient注入异常还是异步行为导致。请问该如何正确测试?
报错信息
java.lang.AssertionError: No further requests expected: HTTP GET https://api.foo.com/get-info 0 request(s) executed
相关代码
业务服务类 MyService
@Service public class MyService { private final Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired RestClient restClient; @Autowired MyRepository repository; @Async public CompletableFuture<Void> fetch(Entity e) { List<MyDto> info = restClient .get() .uri("/get-info" + e.getId()) .attributes(clientRegistrationId("oauth2-client")) .retrieve() .body(new ParameterizedTypeReference<List<MyDto>>() {}); repository.saveAll(info); return CompletableFuture.completedFuture(null); } }
测试类 MyServiceTest
@RestClientTest({MyService.class}) @Import({MyServiceTest.TestConfig.class}) class MyServiceTest { @TestConfiguration static class TestConfig { @Bean ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(ClientRegistration.withRegistrationId("oauth2-client") .authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS) .clientId("test") .tokenUri("test") .build()); } @Bean OAuth2AuthorizedClientService auth2AuthorizedClientService( ClientRegistrationRepository clientRegistrationRepository) { return new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); } @Bean public Executor asyncTaskExecutor() { return new SyncTaskExecutor(); } @Bean public RestClient restClient(RestClient.Builder restClientBuilder) { return restClientBuilder .baseUrl("https://api.foo.com") .defaultHeader("X-API-KEY", "test-api-key") .build(); } } MockRestServiceServer server; @MockBean MyRepository myRepository; @Autowired private MyService service; @Autowired RestClient.Builder restClientBuilder; @BeforeEach void setUp() { server = MockRestServiceServer.bindTo(restClientBuilder).build(); } @Test void testFetch() { Entity e = new Entity(); e.setId(1L); server.expect(requestTo("https://api.foo.com/get-info")) .andRespond( withSuccess().contentType(MediaType.APPLICATION_JSON)); service.fetch(e).join(); server.verify(); } }
RestClient配置类 RestClientConfig
@Configuration public class RestClientConfig { @Value("${api.key}") private String apiKey; @Bean public OAuth2AuthorizedClientManager authorizedClientManager( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) { AuthorizedClientServiceOAuth2AuthorizedClientManager authorizedClientManager = new AuthorizedClientServiceOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); authorizedClientManager.setAuthorizedClientProvider(OAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() .build()); return authorizedClientManager; } @Bean public RestClient restClient(OAuth2AuthorizedClientManager authorizedClientManager) { return RestClient.builder() .baseUrl("https://api.foo.com") .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) .defaultHeader("X-API-KEY", apiKey) .requestInterceptor(new OAuth2ClientHttpRequestInterceptor(authorizedClientManager)) .build(); } }
解决方案
问题主要由3个核心原因导致,逐一修复即可:
1. 绑定MockRestServiceServer的对象错误
测试中绑定的是RestClient.Builder,但业务实际使用的是已构建完成的RestClient实例,导致Mock服务未关联到实际被调用的对象。
修复方式:直接绑定注入的RestClient实例:
@Autowired private RestClient restClient; @BeforeEach void setUp() { server = MockRestServiceServer.bindTo(restClient).build(); }
2. 请求URI不匹配
业务代码中拼接的URI是/get-info + e.getId(),当e.getId()为1时,实际请求地址是https://api.foo.com/get-info1,但测试里期望的是https://api.foo.com/get-info,URI不匹配导致Mock服务判定无请求。
修复测试中的期望地址:
server.expect(requestTo("https://api.foo.com/get-info1")) .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON));
或使用匹配器增强灵活性:
server.expect(requestTo(endsWith("/get-info1"))) .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON));
3. RestClient配置缺失OAuth2拦截器
测试类的TestConfig中构建的RestClient未添加OAuth2ClientHttpRequestInterceptor,与业务代码中的RestClient配置不一致,可能导致请求流程异常。
修复TestConfig中的RestClient Bean:
@Bean public RestClient restClient(RestClient.Builder restClientBuilder, OAuth2AuthorizedClientManager authorizedClientManager) { return restClientBuilder .baseUrl("https://api.foo.com") .defaultHeader("X-API-KEY", "test-api-key") .requestInterceptor(new OAuth2ClientHttpRequestInterceptor(authorizedClientManager)) .build(); }
额外修正点
- 测试类中
@Autowired private Service service;需改为@Autowired private MyService service;,修正类名错误。 - 业务类中
@Autowired MyRepository需补充变量名,改为@Autowired MyRepository repository;。
修复后测试类即可正确检测到请求并通过验证。
内容的提问来源于stack exchange,提问作者udduu
相关产品推荐
相关产品推荐

