查看文档here,用于
RestClient
的预期模式是自动装配 RestClient.Builder
,然后在服务的构造函数方法中构建 RestClient
。虽然这在常规课程中使用时效果很好,但在测试时效果不佳。
根据文档here,当应用程序中仅使用 1 个构建器时,
@RestClientTest
和 @AutoConfigureMockRestServiceServer
可用。随着创建更多实例并且需要特定的自定义,很明显您将希望为每一项特定服务拥有多个 RestClient.Builder
。
有了这个,我能看到配置它的唯一方法是将
MockRestServiceServer
绑定到每个 RestClient.Builder
使得将它们作为 beans 似乎是显而易见的路线。现在您可以拥有如下代码:
配置逻辑:
@RequiredArgsConstructor
@Configuration
public class RestClientConfiguration {
private final RestClientBuilderConfigurer restClientBuilderConfigurer;
@Bean
RestClient.Builder microservice1RestClientBuilder() {
return createDefaultRestClientBuilder()
.baseUrl("http://localhost:8081");
}
/**
* Copied from
* {@link org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration
* RestClientAutoConfiguration}
*
* @return
*/
private RestClient.Builder createDefaultRestClientBuilder() {
RestClient.Builder builder = RestClient
.builder()
.requestFactory(ClientHttpRequestFactories.get(ClientHttpRequestFactorySettings.DEFAULTS));
return restClientBuilderConfigurer.configure(builder);
}
}
控制器逻辑:
@RequiredArgsConstructor
@RestController
public class MainController {
private final MainService mainService;
@GetMapping
public String hello() {
return mainService.helloService();
}
}
服务逻辑:
@Service
public class MainService {
private final RestClient restClient;
public MainService(RestClient.Builder microservice1RestClientBuilder) {
super();
restClient = microservice1RestClientBuilder.build();
}
public String helloService() {
return restClient.get().uri("/").retrieve().body(String.class);
}
}
测试逻辑:
@SpringBootTest
@AutoConfigureMockMvc
class MainControllerTest {
private MockRestServiceServer microservice1Server;
@Autowired
private RestClient.Builder microservice1RestClientBuilder;
@Autowired
private MockMvc mvc;
@BeforeEach
void init() {
microservice1Server = MockRestServiceServer.bindTo(microservice1RestClientBuilder).build();
}
@Test
void test() throws Exception {
microservice1Server
.expect(requestTo("http://localhost:8081/"))
.andRespond(withSuccess("Hello world", MediaType.TEXT_PLAIN));
mvc.perform(get("/")).andExpect(status().is2xxSuccessful()).andExpect(content().string("Hello world"));
}
}
这一切看起来应该可以工作,但事实并非如此,因为在创建
RestClient
之前测试不会绑定。要解决此问题,可以将服务类更改为以下内容,测试将开始工作。
@RequiredArgsConstructor
@Service
public class MainService {
private final RestClient.Builder microservice1RestClientBuilder;
public String helloService() {
return microservice1RestClientBuilder.build().get().uri("/").retrieve().body(String.class);
}
}
测试用例现在可以工作,但是现在每次调用都会创建
RestClient
,这感觉没有必要。这让我相信要么我错过了它的预期使用方式,要么在某个地方存在差距。我对这个问题的希望是展示使用 RestClient
的最佳方法,不仅用于一般用途,而且还用于测试目的。
你是对的,
@AutoConfigureMockMvc
在这种情况下不起作用。看起来使用 MockServerRestClientCustomizer
会带来最好的运气。该类的 javadoc 显示了其用法示例,并且有 集成测试用例 也可以用作示例。
使用这种技术,你的测试类可能看起来像这样:
@SpringBootTest
class MainControllerTest {
@Autowired
private MainService mainService;
@Autowired
private MockServerRestClientCustomizer customizer;
@Autowired
private MockMvc mvc;
@Test
void test() throws Exception {
this.customizer.getServer(this.mainService.getRestClientBuilder())
.expect(requestTo("http://localhost:8081/"))
.andRespond(withSuccess("Hello world", MediaType.TEXT_PLAIN));
mvc.perform(get("/"))
.andExpect(status().is2xxSuccessful())
.andExpect(content().string("Hello world"));
}
}