我正在尝试使用Spring 5路由将Spring Cloud Contract与Rest Service结合使用,但是它不起作用。 我在客户端,并且尝试在junit测试中使用存根运行器。 如果我使用经典的@RestController和助焊剂,它可以正常工作,但是如果我尝试使用RouterFunction更改控制器,它将无法正常工作,并且我会得到404。 这是我的示例代码。
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Routing.java
@Configuration
@EnableWebFlux
public class Routing {
@Autowired
private TestLoginController loginController;
@Bean
public HttpHandler routerFunction() {
return WebHttpHandlerBuilder
.webHandler(RouterFunctions.toWebHandler(createRouterFunction()))
.build();
}
private RouterFunction<ServerResponse> createRouterFunction() {
return route(POST("/testlogin"), loginController::testLogin);
}
}
TestLoginController.java
@Component
public class TestLoginController {
@Autowired
private TestLoginService testLoginService;
public Mono<ServerResponse> testLogin(ServerRequest request) {
return Mono.just(request)
.flatMap(req -> ServerResponse.ok()
.body(testLoginService.testLogin(request.bodyToMono(LoginRequest.class)), LoginResponse.class)
);
}
}
DemoApplicationTest.java
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureStubRunner(ids = {"groupId:artifactId:+:stubs:8090"},
stubsMode = StubRunnerProperties.StubsMode.LOCAL)
public class DemoApplicationTests {
@LocalServerPort
private int port;
@Test
public void contextLoads() throws Exception {
LoginRequest request = new LoginRequest();
WebTestClient
.bindToServer()
.baseUrl("http://localhost:" + port)
.build()
.post()
.uri("testlogin").accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromObject(request))
.exchange()
.expectStatus().isOk()
.expectBody()
....
}
}
即使删除@AutoConfigureStubRunner批注,我也遇到相同的问题。如果我只添加存根运行程序依赖项,我会发现此行为,我会发现此问题。 我也尝试使用Spring Boot和Spring Cloud Contract的最新版本,但是我遇到了同样的问题。有人可以帮助我吗?
答案 0 :(得分:0)
Spring Cloud Contract Stub Runner仅在给定(或随机端口)上启动WireMock服务器。 Stub Runner没有发生与WebTestClient
相关的任何事情。换句话说,很可能您配置了WebTestClient
。
让我们确保您不会滥用该项目。如果您有服务A通过WebClient调用服务B,则服务B应该定义了合同,可以从中创建测试和跨度。然后在服务A端,您将使用Spring Cloud Contract Stub Runner启动服务B的存根。无论您使用什么(RestTemplate,WebClient等),您仍将向我们为您启动的WireMock服务器发送HTTP调用。 / p>
如何将Spring Cloud Contract Stub Runner与WebTestClient一起使用的示例(摘自:https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/master/consumer/src/test/java/com/example/BeerControllerWebClientTest.java)
package com.example;
import java.util.Objects;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerPort;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;
/**
* @author Marcin Grzejszczak
*/
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
@AutoConfigureMockMvc
@AutoConfigureJsonTesters
//remove::start[]
@AutoConfigureStubRunner(stubsMode = StubRunnerProperties.StubsMode.LOCAL, ids = "com.example:beer-api-producer-webflux")
//remove::end[]
@DirtiesContext
//@org.junit.Ignore
public class BeerControllerWebClientTest extends AbstractTest {
//remove::start[]
@StubRunnerPort("beer-api-producer-webflux") int producerPort;
//remove::end[]
@Test public void should_give_me_a_beer_when_im_old_enough() throws Exception {
//remove::start[]
WebTestClient.bindToServer()
.build()
.post()
.uri("http://localhost:" + producerPort + "/check")
.syncBody(new WebClientPerson("marcin", 22))
.header("Content-Type", "application/json")
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(WebClientResponse.class)
.isEqualTo(new WebClientResponse(WebClientResponseStatus.OK));
//remove::end[]
}
@Test public void should_reject_a_beer_when_im_too_young() throws Exception {
//remove::start[]
WebTestClient.bindToServer()
.build()
.post()
.uri("http://localhost:" + producerPort + "/check")
.syncBody(new WebClientPerson("marcin", 17))
.header("Content-Type", "application/json")
.exchange()
.expectStatus().is2xxSuccessful()
.expectBody(WebClientResponse.class)
.isEqualTo(new WebClientResponse(WebClientResponseStatus.NOT_OK));
//remove::end[]
}
}
class WebClientPerson {
public String name;
public int age;
public WebClientPerson(String name, int age) {
this.name = name;
this.age = age;
}
public WebClientPerson() {
}
}
class WebClientResponse {
public WebClientResponseStatus status;
WebClientResponse(WebClientResponseStatus status) {
this.status = status;
}
WebClientResponse() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
WebClientResponse that = (WebClientResponse) o;
return status == that.status;
}
@Override
public int hashCode() {
return Objects.hash(status);
}
}
enum WebClientResponseStatus {
OK, NOT_OK
}