Я пытаюсь использовать весенний облачный контракт с сервисом отдыха, используя маршрутизацию Spring 5, но это не работает. Я на стороне клиента, и я пытаюсь использовать программу-заглушку в тесте 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 Cloud Contract Stub Runner просто запускает сервер WireMock на заданном (или случайном порте). Ничего связанного с WebTestClient не происходит с Stub Runner. Другими словами, скорее всего, вы неправильно сконфигурировали WebTestClient.
Попробуем убедиться, что вы не злоупотребляете проектом. Если у вас есть служба A, вызывающая службу B через WebClient, тогда для службы B должны быть определены контракты, из которых будут создаваться тесты и интервалы. Затем на стороне службы A вы будете использовать Spring Cloud Contract Stub Runner для запуска заглушек службы B. Что бы вы ни использовали (RestTemplate, WebClient, что угодно), вы все равно будете отправлять HTTP-вызов на сервер WireMock, который мы запускаем для вас.
Пример использования 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
}
я думаю, что это то, что я сделал. Я создаю отличный контракт на стороне производителя, я запускаю команду mvn install, чтобы сгенерировать заглушку. в моем потребителе у меня есть служба, которая вызывает производителя по указанному URL-адресу. Я настроил программу-заглушку для запуска по этому URL-адресу и запуска теста. где я не прав? У меня есть 404, даже если я удалю аннотацию автонастройки stub runner, но у меня есть stub runner starter в моей зависимости
я уже видел этот пример. но я на стороне потребителя, а не производителя
Обновил ответ с помощью прохождения теста, который я добавил в образцы
я попробую сделать другой тест. но моя конфигурация веб-клиента - это то, что вы видите в моем первом посте. Если я создаю тест, который вызывает только потребителя, он работает хорошо. когда я добавляю зависимость от заглушки (без добавления конфигурации в тест), тест завершается неудачно. Спасибо за ответы
Спасибо @MarcinGrzejszczak. Не могли бы вы помочь мне понять, следует ли мне издеваться над контроллером / службами или вводить настоящий? В примерах вы приводите реальную реализацию, поэтому запутались. Нашему сервису требуется подключение к базе данных.
Вы должны предоставить реальные контроллеры с имитацией сервисов (пример: github.com/spring-cloud-samples/spring-cloud-contract-sample s /…, где мы вводим лямбду с фальшивым сервисом)
Я удалил @AutoConfigureStubRunner, и он отлично работал с маршрутами.