Hợp đồng theo hướng người tiêu dùng với Pact

1. Khái quát chung

Trong bài viết nhanh này, chúng ta sẽ xem xét khái niệm về Hợp đồng dựa vào người tiêu dùng.

Chúng tôi sẽ thử nghiệm tích hợp với dịch vụ REST bên ngoài thông qua hợp đồng mà chúng tôi xác định bằng cách sử dụng thư viện Pact . Hợp đồng đó có thể được xác định bởi khách hàng, sau đó được nhà cung cấp chọn và sử dụng để phát triển các dịch vụ của mình.

Chúng tôi cũng sẽ tạo các thử nghiệm dựa trên hợp đồng cho cả ứng dụng khách và ứng dụng của nhà cung cấp.

2. Pact là gì?

Sử dụng Pact , chúng tôi có thể xác định kỳ vọng của người tiêu dùng đối với một nhà cung cấp nhất định (có thể là dịch vụ HTTP REST) ​​dưới dạng hợp đồng (do đó có tên là thư viện).

Chúng tôi sẽ thiết lập hợp đồng này bằng cách sử dụng DSL do Pact cung cấp . Sau khi được xác định, chúng tôi có thể kiểm tra các tương tác giữa người tiêu dùng và nhà cung cấp bằng cách sử dụng dịch vụ giả được tạo dựa trên hợp đồng đã xác định. Ngoài ra, chúng tôi sẽ kiểm tra dịch vụ theo hợp đồng bằng cách sử dụng một ứng dụng khách giả.

3. Sự phụ thuộc Maven

Để bắt đầu, chúng tôi sẽ cần thêm phần phụ thuộc Maven vào thư viện pact-jvm-Consumer-junit_2.11 :

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

4. Xác định Hợp đồng

Khi chúng ta muốn tạo một bài kiểm tra bằng Pact , trước tiên chúng ta cần xác định một @Rule sẽ được sử dụng trong bài kiểm tra của chúng ta:

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

Chúng tôi đang chuyển tên nhà cung cấp, máy chủ và cổng mà mô hình máy chủ (được tạo từ hợp đồng) sẽ được bắt đầu.

Giả sử dịch vụ đó đã xác định hợp đồng cho hai phương thức HTTP mà nó có thể xử lý.

Phương thức đầu tiên là một yêu cầu GET trả về JSON với hai trường. Khi yêu cầu thành công, nó trả về mã phản hồi 200 HTTP và tiêu đề C ontent-Type cho JSON.

Hãy xác định một hợp đồng như vậy bằng cách sử dụng Pact .

Chúng tôi cần sử dụng chú thích @Pact và chuyển tên người tiêu dùng mà hợp đồng được xác định. Bên trong phương thức được chú thích, chúng ta có thể xác định hợp đồng GET của mình:

@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\"}") (...) }

Sử dụng Pact DSL, chúng tôi xác định rằng đối với một yêu cầu GET nhất định, chúng tôi muốn trả về một phản hồi 200 với các tiêu đề và nội dung cụ thể.

Phần thứ hai trong hợp đồng của chúng tôi là phương thức POST. Khi máy khách gửi một yêu cầu POST đến đường dẫn / pact với phần thân JSON thích hợp, nó sẽ trả về mã phản hồi HTTP 201.

Hãy xác định hợp đồng như vậy với Pact:

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

Lưu ý rằng chúng ta cần gọi phương thức toPact () ở cuối hợp đồng để trả về một phiên bản của RequestResponsePact .

4.1. Phần mềm Pact kết quả

Theo mặc định, các tệp Pact sẽ được tạo trong thư mục target / pacts . Để tùy chỉnh đường dẫn này, chúng ta có thể định cấu hình maven-surefire-plugin:

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

Bản dựng Maven sẽ tạo một tệp có tên test_consumer-test_provider.json trong thư mục target / mypacts chứa cấu trúc của các yêu cầu và phản hồi:

{ "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. Kiểm tra khách hàng và nhà cung cấp bằng cách sử dụng hợp đồng

Bây giờ chúng tôi đã có hợp đồng của mình, chúng tôi có thể sử dụng để tạo các thử nghiệm chống lại nó cho cả khách hàng và nhà cung cấp.

Mỗi bài kiểm tra này sẽ sử dụng một mô hình của đối tác của nó dựa trên hợp đồng, nghĩa là:

  • khách hàng sẽ sử dụng một nhà cung cấp giả
  • nhà cung cấp sẽ sử dụng một khách hàng giả

Hiệu quả, các thử nghiệm được thực hiện trái với hợp đồng.

5.1. Kiểm tra khách hàng

Sau khi xác định hợp đồng, chúng tôi có thể kiểm tra các tương tác với dịch vụ sẽ được tạo dựa trên hợp đồng đó. Chúng ta có thể tạo thử nghiệm JUnit bình thường nhưng chúng ta cần nhớ đặt chú thích @PactVerification ở đầu thử nghiệm.

Hãy viết một bài kiểm tra cho yêu cầu 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"); }

Các @PactVerification chú thích chăm sóc bắt đầu dịch vụ HTTP. Trong thử nghiệm, chúng tôi chỉ cần gửi yêu cầu GET và khẳng định rằng phản hồi của chúng tôi tuân thủ hợp đồng.

Hãy thêm thử nghiệm cho lệnh gọi phương thức 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);

Như chúng ta có thể thấy, mã phản hồi cho yêu cầu POST bằng 201 - chính xác như nó đã được định nghĩa trong hợp đồng Pact .

Khi chúng tôi đang sử dụng chú thích @PactVerification () , thư viện Pact đang khởi động máy chủ web dựa trên hợp đồng đã xác định trước đó trước trường hợp thử nghiệm của chúng tôi.

5.2. Kiểm tra nhà cung cấp

Bước thứ hai của quá trình xác minh hợp đồng của chúng tôi là tạo thử nghiệm cho nhà cung cấp bằng cách sử dụng một khách hàng giả dựa trên hợp đồng.

Việc triển khai nhà cung cấp của chúng tôi sẽ được thúc đẩy bởi hợp đồng này theo kiểu TDD.

Đối với ví dụ của chúng tôi, chúng tôi sẽ sử dụng một API REST Spring Boot.

Đầu tiên, để tạo thử nghiệm JUnit của chúng tôi, chúng tôi sẽ cần thêm phụ thuộc pact-jvm-provider-junit_2.11:

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

Điều này cho phép chúng tôi tạo thử nghiệm JUnit bằng PactRunner và chỉ định tên nhà cung cấp và vị trí của tạo tác Pact:

@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.

Chúng tôi đã tạo một hợp đồng bằng cách sử dụng thư viện Pact . Sau khi xác định hợp đồng, chúng tôi có thể kiểm tra khách hàng và dịch vụ so với hợp đồng và khẳng định rằng họ tuân thủ đặc điểm kỹ thuật.

Việc triển khai tất cả các ví dụ và đoạn mã này có thể được tìm thấy trong dự án GitHub - đây là một dự án Maven, vì vậy nó sẽ dễ dàng nhập và chạy như nó vốn có.