1. введение
Весенний Облачный контракт это проект, который, проще говоря, помогает нам писать Контракты, ориентированные на потребителей (CDC) .
Это обеспечивает контракт между Производителем и Потребителем в распределенной системе – как для взаимодействия на основе HTTP , так и для взаимодействия на основе сообщений.
В этой краткой статье мы рассмотрим написание тестовых примеров на стороне производителя и потребителя для Spring Cloud Contract с помощью HTTP-взаимодействия.
2. Сторона Производителя – Сервер
Мы собираемся написать CDC на стороне производителя в виде EvenOddController – который просто сообщает, является ли параметр number четным или нечетным:
@RestController public class EvenOddController { @GetMapping("/validate/prime-number") public String isNumberPrime(@RequestParam("number") Integer number) { return Integer.parseInt(number) % 2 == 0 ? "Even" : "Odd"; } }
2.1. Зависимости Maven
Для нашей стороны производителя нам понадобится spring-cloud-starter-contract-verifier зависимость:
org.springframework.cloud spring-cloud-starter-contract-verifier 2.1.1.RELEASE test
И нам нужно будет настроить spring-cloud-contract-maven-plugin с именем нашего базового тестового класса, который мы опишем в следующем разделе:
org.springframework.cloud spring-cloud-contract-maven-plugin 2.1.1.RELEASE true com.baeldung.spring.cloud.springcloudcontractproducer.BaseTestClass
2.2. Настройка на стороне производителя
Нам нужно добавить базовый класс в тестовый пакет, который загружает наш контекст Spring:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @DirtiesContext @AutoConfigureMessageVerifier public class BaseTestClass { @Autowired private EvenOddController evenOddController; @Before public void setup() { StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(evenOddController); RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder); } }
В пакете /src/test/resources/contracts/ мы добавим заглушки тестов , такие как этот в файле shouldReturnEvenWhenRequestParamIsEven.groovy :
import org.springframework.cloud.contract.spec.Contract Contract.make { description "should return even when number input is even" request{ method GET() url("/validate/prime-number") { queryParameters { parameter("number", "2") } } } response { body("Even") status 200 } }
Когда мы запускаем сборку, плагин автоматически генерирует тестовый класс с именем Contract Verifier Test , который расширяет наш BaseTestClass и помещает его в /target/generated-test-sources/contracts/|.
Имена методов тестирования являются производными от префикса ” validate_” , объединенного с именами наших заводных тестовых заглушек. Для приведенного выше файла Groovy сгенерированное имя метода будет “validate_should Return Even When RequestParam Является четным” .
Давайте взглянем на этот автоматически сгенерированный тестовый класс:
public class ContractVerifierTest extends BaseTestClass { @Test public void validate_shouldReturnEvenWhenRequestParamIsEven() throws Exception { // given: MockMvcRequestSpecification request = given(); // when: ResponseOptions response = given().spec(request) .queryParam("number","2") .get("/validate/prime-number"); // then: assertThat(response.statusCode()).isEqualTo(200); // and: String responseBody = response.getBody().asString(); assertThat(responseBody).isEqualTo("Even"); }
Сборка также добавит заглушку в ваш локальный репозиторий Maven, чтобы он мог использоваться нашим потребителем.
Заглушки будут присутствовать в выходной папке в разделе заглушки/сопоставление/|/.
3. Сторона Потребителя – Клиента
Потребительская сторона нашего CDC будет потреблять заглушки, созданные стороной производителя через HTTP-взаимодействие для поддержания контракта, поэтому любые изменения на стороне производителя нарушат контракт .
Мы добавим Базовый математический контроллер, который сделает HTTP-запрос, чтобы получить ответ от сгенерированных заглушек:
@RestController public class BasicMathController { @Autowired private RestTemplate restTemplate; @GetMapping("/calculate") public String checkOddAndEven(@RequestParam("number") Integer number) { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Content-Type", "application/json"); ResponseEntityresponseEntity = restTemplate.exchange( "http://localhost:8090/validate/prime-number?number=" + number, HttpMethod.GET, new HttpEntity<>(httpHeaders), String.class); return responseEntity.getBody(); } }
3.1. Зависимости Maven
Для нашего потребителя нам нужно будет добавить зависимости spring-cloud-contract-wiremock и spring-cloud-contract-stub-runner :
org.springframework.cloud spring-cloud-contract-wiremock 2.1.1.RELEASE test org.springframework.cloud spring-cloud-contract-stub-runner 2.1.1.RELEASE test
3.2. Настройка На Стороне потребителя
Теперь пришло время настроить свой stub runner, который будет информировать нашего потребителя о доступных заглушках в нашем локальном репозитории Maven:
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) @AutoConfigureMockMvc @AutoConfigureJsonTesters @AutoConfigureStubRunner( stubsMode = StubRunnerProperties.StubsMode.LOCAL, ids = "com.baeldung.spring.cloud:spring-cloud-contract-producer:+:stubs:8090") public class BasicMathControllerIntegrationTest { @Autowired private MockMvc mockMvc; @Test public void given_WhenPassEvenNumberInQueryParam_ThenReturnEven() throws Exception { mockMvc.perform(MockMvcRequestBuilders.get("/calculate?number=2") .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) .andExpect(content().string("Even")); } }
Обратите внимание, что свойство ids аннотации @AutoConfigureStubRunner указывает:
- com.baeldung.spring.cloud —/| groupId нашего артефакта spring-cloud-contract-producer
- — the artifactId из банки-заглушки производителя 8090
- — порт, на котором будут выполняться сгенерированные заглушки
4. Когда Контракт Нарушен
Если мы внесем какие-либо изменения на стороне производителя, которые непосредственно влияют на контракт, не обновляя сторону потребителя, это может привести к срыву контракта.
Например, предположим, что мы должны изменить Четный нечетный контроллер запросить URI на /проверить/изменить/простое число на стороне производителя.
Если мы не сообщим нашему потребителю об этом изменении, потребитель все равно отправит свой запрос в /validate/prime-number URI, и тестовые случаи на стороне потребителя будут выдавать org.springframework.web.client.HttpClientErrorException: 404 Не найден .
5. Резюме
Мы видели, как Spring Cloud Contract может помочь нам поддерживать контракты между потребителем услуг и производителем, чтобы мы могли выпускать новый код, не беспокоясь о нарушении контрактов.
И, как всегда, полную реализацию этого учебника можно найти на GitHub .