Pact와의 소비자 주도 계약

1. 개요

이 빠른 기사에서는 소비자 주도 계약의 개념을 살펴볼 것입니다.

Pact 라이브러리를 사용하여 정의한 계약을 통해 외부 REST 서비스와의 통합을 테스트 할 것 입니다. 이 계약은 클라이언트가 정의한 다음 공급자가 선택하여 서비스 개발에 사용할 수 있습니다.

또한 클라이언트 및 공급자 응용 프로그램에 대한 계약을 기반으로 테스트를 생성합니다.

2. Pact 란?

사용 협정을 , 우리는 계약의 형태로 주어진 공급자에 대한 소비자의 기대 (즉, 될 수있는 HTTP의 REST 서비스) 정의 할 수 있습니다 (라이브러리 따라서 이름을).

Pact에서 제공하는 DSL을 사용하여이 계약을 설정할 것 입니다. 일단 정의되면 정의 된 계약을 기반으로 생성 된 모의 서비스를 사용하여 소비자와 공급자 간의 상호 작용을 테스트 할 수 있습니다. 또한 모의 클라이언트를 사용하여 계약에 대해 서비스를 테스트합니다.

3. Maven 종속성

시작하려면 pact-jvm-consumer-junit_2.11 라이브러리 에 Maven 종속성을 추가해야합니다 .

 au.com.dius pact-jvm-consumer-junit_2.11 3.5.0 test 

4. 계약 정의

Pact 를 사용하여 테스트를 만들려면 먼저 테스트에 사용할 @Rule 을 정의해야합니다 .

@Rule public PactProviderRuleMk2 mockProvider = new PactProviderRuleMk2("test_provider", "localhost", 8080, this);

서버 모의 (계약에서 생성됨)가 시작될 공급자 이름, 호스트 및 포트를 전달합니다.

서비스가 처리 할 수있는 두 가지 HTTP 메서드에 대한 계약을 정의했다고 가정 해 보겠습니다.

첫 번째 방법은 두 필드가있는 JSON을 반환하는 GET 요청입니다. 요청이 성공하면 200 HTTP 응답 코드와 JSON에 대한 C ontent-Type 헤더를 반환합니다 .

Pact를 사용하여 이러한 계약을 정의 해 보겠습니다 .

@Pact 주석 을 사용 하고 계약이 정의 된 소비자 이름을 전달해야합니다. 주석이 추가 된 메서드 내에서 GET 계약을 정의 할 수 있습니다.

@Pact(consumer = "test_consumer") public RequestResponsePact createPact(PactDslWithProvider builder) { Map headers = new HashMap(); headers.put("Content-Type", "application/json"); return builder .given("test GET") .uponReceiving("GET REQUEST") .path("/pact") .method("GET") .willRespondWith() .status(200) .headers(headers) .body("{\"condition\": true, \"name\": \"tom\"}") (...) }

은 Using 협정 DSL을 우리는 우리가 특정 헤더와 시체와 함께 200 응답을 반환하려면 주어진 GET 요청에 대한 것을 정의한다.

계약의 두 번째 부분은 POST 메서드입니다. 클라이언트 가 적절한 JSON 본문과 함께 / pact 경로로 POST 요청을 보내면 201 HTTP 응답 코드를 반환합니다.

이러한 계약을 Pact 와 정의 해 보겠습니다 .

(...) .given("test POST") .uponReceiving("POST REQUEST") .method("POST") .headers(headers) .body("{\"name\": \"Michael\"}") .path("/pact") .willRespondWith() .status(201) .toPact();

RequestResponsePact 인스턴스를 반환하려면 계약 종료시 toPact () 메서드 를 호출해야합니다 .

4.1. 결과 조약 유물

기본적으로 Pact 파일은 target / pacts 폴더에 생성됩니다 . 이 경로를 사용자 지정하기 위해 maven-surefire-plugin을 구성 할 수 있습니다 .

 org.apache.maven.plugins maven-surefire-plugin   target/mypacts   ... 

Maven 빌드는 요청 및 응답의 구조를 포함하는 target / mypacts 폴더 에 test_consumer-test_provider.json 이라는 파일을 생성합니다 .

{ "provider": { "name": "test_provider" }, "consumer": { "name": "test_consumer" }, "interactions": [ { "description": "GET REQUEST", "request": { "method": "GET", "path": "/" }, "response": { "status": 200, "headers": { "Content-Type": "application/json" }, "body": { "condition": true, "name": "tom" } }, "providerStates": [ { "name": "test GET" } ] }, { "description": "POST REQUEST", ... } ], "metadata": { "pact-specification": { "version": "3.0.0" }, "pact-jvm": { "version": "3.5.0" } } }

5. 계약을 사용하여 클라이언트 및 공급자 테스트

이제 계약이 완료되었으므로 클라이언트와 공급자 모두에 대한 테스트를 생성하는 데 사용할 수 있습니다.

이러한 각 테스트는 계약을 기반으로하는 모의를 사용합니다.

  • 클라이언트는 모의 공급자를 사용합니다.
  • 공급자는 모의 클라이언트를 사용합니다.

사실상 테스트는 계약에 대해 수행됩니다.

5.1. 클라이언트 테스트

계약을 정의하면 해당 계약을 기반으로 생성 될 서비스와의 상호 작용을 테스트 할 수 있습니다. 일반 JUnit 테스트를 만들 수 있지만 테스트 시작 부분에 @PactVerification 주석 을 넣는 것을 기억해야합니다 .

GET 요청에 대한 테스트를 작성해 보겠습니다.

@Test @PactVerification() public void givenGet_whenSendRequest_shouldReturn200WithProperHeaderAndBody() { // when ResponseEntity response = new RestTemplate() .getForEntity(mockProvider.getUrl() + "/pact", String.class); // then assertThat(response.getStatusCode().value()).isEqualTo(200); assertThat(response.getHeaders().get("Content-Type").contains("application/json")).isTrue(); assertThat(response.getBody()).contains("condition", "true", "name", "tom"); }

@PactVerification의 주석은 HTTP 서비스를 시작을 담당한다. 테스트에서는 GET 요청을 보내고 응답이 계약을 준수한다고 주장하기 만하면됩니다.

POST 메서드 호출에 대한 테스트도 추가해 보겠습니다.

HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); String jsonBody = "{\"name\": \"Michael\"}"; // when ResponseEntity postResponse = new RestTemplate() .exchange( mockProvider.getUrl() + "/create", HttpMethod.POST, new HttpEntity(jsonBody, httpHeaders), String.class ); //then assertThat(postResponse.getStatusCode().value()).isEqualTo(201);

보시다시피 POST 요청에 대한 응답 코드는 Pact 계약 에 정의 된대로 정확히 201 입니다.

As we were using the @PactVerification() annotation, the Pact library is starting the web server based on the previously defined contract before our test case.

5.2. Testing the Provider

The second step of our contract verification is creating a test for the provider using a mock client based on the contract.

Our provider implementation will be driven by this contract in TDD fashion.

For our example, we'll use a Spring Boot REST API.

First, to create our JUnit test, we'll need to add the pact-jvm-provider-junit_2.11 dependency:

 au.com.dius pact-jvm-provider-junit_2.11 3.5.0 test 

This allows us to create a JUnit test using the PactRunner and specifying the provider name and the location of the Pact artifact:

@RunWith(PactRunner.class) @Provider("test_provider") @PactFolder("pacts") public class PactProviderTest { //... }

For this configuration to work, we have to place the test_consumer-test_provider.json file in the pacts folder of our REST service project.

Next, we'll define the target to be used for verifying the interactions in the contract and start up the Spring Boot app before running the tests:

@TestTarget public final Target target = new HttpTarget("http", "localhost", 8082, "/spring-rest"); private static ConfigurableWebApplicationContext application; @BeforeClass public static void start() { application = (ConfigurableWebApplicationContext) SpringApplication.run(MainApplication.class); }

Finally, we'll specify the states in the contract that we want to test:

@State("test GET") public void toGetState() { } @State("test POST") public void toPostState() { }

Running this JUnit class will execute two tests for the two GET and POST requests. Let's take a look at the log:

Verifying a pact between test_consumer and test_provider Given test GET GET REQUEST returns a response which has status code 200 (OK) includes headers "Content-Type" with value "application/json" (OK) has a matching body (OK) Verifying a pact between test_consumer and test_provider Given test POST POST REQUEST returns a response which has status code 201 (OK) has a matching body (OK)

Note that we haven't included the code for creating a REST service here. The full service and test can be found in the GitHub project.

6. Conclusion

In this quick tutorial, we had a look at Consumer Driven Contracts.

우리는 Pact 라이브러리를 사용하여 계약을 만들었습니다 . 계약을 정의한 후에는 계약에 대해 클라이언트와 서비스를 테스트하고 사양을 준수한다고 주장 할 수있었습니다.

이러한 모든 예제 및 코드 스 니펫의 구현은 GitHub 프로젝트에서 찾을 수 있습니다. 이것은 Maven 프로젝트이므로 그대로 가져 와서 실행할 수 있어야합니다.