Pengenalan kepada WireMock

1. Gambaran keseluruhan

WireMock adalah perpustakaan untuk menyekat dan mengejek perkhidmatan web. Ia membina pelayan HTTP yang dapat kami sambungkan seperti yang kami lakukan ke perkhidmatan web yang sebenarnya.

Apabila pelayan WireMock beraksi, kita dapat menetapkan harapan, memanggil perkhidmatan, dan kemudian mengesahkan tingkah lakunya.

2. Pergantungan Maven

Untuk dapat memanfaatkan perpustakaan WireMock, kita perlu memasukkan kebergantungan berikut dalam POM:

 com.github.tomakehurst wiremock 1.58 test 

3. Pelayan Terurus Terprogram

Bahagian ini akan merangkumi cara untuk mengkonfigurasi pelayan WireMock secara manual. iaitu tanpa sokongan konfigurasi automatik JUnit. Penggunaan ditunjukkan oleh rintisan yang sangat sederhana.

3.1. Penyediaan Pelayan

Pelayan WireMock boleh dibuat seperti ini:

WireMockServer wireMockServer = new WireMockServer(String host, int port);

Sekiranya tidak ada argumen yang diberikan, host pelayan secara lalai ke localhost dan port pelayan ke 8080 .

Pelayan kemudian boleh dimulakan dan dihentikan menggunakan dua kaedah mudah:

wireMockServer.start();

Dan:

wireMockServer.stop();

3.2. Penggunaan Asas

Perpustakaan WireMock pertama kali akan ditunjukkan oleh penggunaan dasar, di mana rintisan untuk URL yang tepat tanpa konfigurasi lebih lanjut disediakan. Mari buat contoh pelayan:

WireMockServer wireMockServer = new WireMockServer();

Pelayan WireMock mesti dijalankan sebelum pelanggan menyambung ke sana:

wireMockServer.start();

Perkhidmatan web kemudian dihentikan:

configureFor("localhost", 8080); stubFor(get(urlEqualTo("/baeldung")).willReturn(aResponse().withBody("Welcome to Baeldung!")));

Tutorial ini menggunakan Apache HttpClient API untuk mewakili klien yang menyambung ke pelayan:

CloseableHttpClient httpClient = HttpClients.createDefault();

Permintaan dilaksanakan dan respons dikembalikan, masing-masing, selepas itu:

HttpGet request = new HttpGet("//localhost:8080/baeldung"); HttpResponse httpResponse = httpClient.execute(request);

Kami akan menukar pemboleh ubah httpResponse ke String menggunakan kaedah pembantu:

String responseString = convertResponseToString(httpResponse);

Berikut adalah pelaksanaan kaedah penolong penukaran itu:

private String convertResponseToString(HttpResponse response) throws IOException { InputStream responseStream = response.getEntity().getContent(); Scanner scanner = new Scanner(responseStream, "UTF-8"); String responseString = scanner.useDelimiter("\\Z").next(); scanner.close(); return responseString; }

Kod berikut mengesahkan bahawa pelayan telah mendapat permintaan ke URL yang diharapkan dan respons yang diterima oleh pelanggan adalah tepat seperti yang dihantar:

verify(getRequestedFor(urlEqualTo("/baeldung"))); assertEquals("Welcome to Baeldung!", stringResponse);

Akhirnya, pelayan WireMock harus dihentikan untuk melepaskan sumber sistem:

wireMockServer.stop();

4. Pelayan Terurus JUnit

Berbeza dengan bahagian 3, bahagian ini menggambarkan penggunaan pelayan WireMock dengan bantuan JUnit Rule .

4.1. Penyediaan Pelayan

Pelayan WireMock dapat diintegrasikan ke dalam kes ujian JUnit dengan menggunakan anotasi @Rule . Ini membolehkan JUnit menguruskan kitaran hidup, memulakan pelayan sebelum setiap kaedah ujian dan menghentikannya setelah kaedah kembali.

Mirip dengan pelayan yang diuruskan secara terprogram, pelayan WireMock yang diuruskan JUnit dapat dibuat sebagai objek Java dengan nombor port yang diberikan:

@Rule public WireMockRule wireMockRule = new WireMockRule(int port);

Sekiranya tidak ada argumen yang diberikan, port pelayan akan mengambil nilai lalai, 8080 . Host pelayan, lalai ke localhost , dan konfigurasi lain mungkin ditentukan menggunakan antara muka Pilihan .

4.2. Pemadanan URL

Setelah menyiapkan contoh WireMockRule , langkah selanjutnya adalah mengkonfigurasi rintisan. Dalam subseksyen ini, kami akan memberikan rintisan REST untuk titik akhir perkhidmatan menggunakan ungkapan biasa:

stubFor(get(urlPathMatching("/baeldung/.*")) .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") .withBody("\"testing-library\": \"WireMock\"")));

Mari beralih ke membuat klien HTTP, melaksanakan permintaan dan menerima respons:

CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("//localhost:8080/baeldung/wiremock"); HttpResponse httpResponse = httpClient.execute(request); String stringResponse = convertHttpResponseToString(httpResponse);

Coretan kod di atas memanfaatkan kaedah penolong penukaran:

private String convertHttpResponseToString(HttpResponse httpResponse) throws IOException { InputStream inputStream = httpResponse.getEntity().getContent(); return convertInputStreamToString(inputStream); }

Ini seterusnya menggunakan kaedah peribadi lain:

private String convertInputStreamToString(InputStream inputStream) { Scanner scanner = new Scanner(inputStream, "UTF-8"); String string = scanner.useDelimiter("\\Z").next(); scanner.close(); return string; }

The stub's operations are verified by the testing code below:

verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(200, httpResponse.getStatusLine().getStatusCode()); assertEquals("application/json", httpResponse.getFirstHeader("Content-Type").getValue()); assertEquals("\"testing-library\": \"WireMock\"", stringResponse);

4.3. Request Header Matching

Now we will demonstrate how to stub a REST API with the matching of headers. Let's start with the stub configuration:

stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .withHeader("Accept", matching("text/.*")) .willReturn(aResponse() .withStatus(503) .withHeader("Content-Type", "text/html") .withBody("!!! Service Unavailable !!!")));

Similar to the preceding subsection, we illustrate HTTP interaction using the HttpClient API, with help of the same helper methods:

CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("//localhost:8080/baeldung/wiremock"); request.addHeader("Accept", "text/html"); HttpResponse httpResponse = httpClient.execute(request); String stringResponse = convertHttpResponseToString(httpResponse);

The following verification and assertions confirm functions of the stub we created before:

verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(503, httpResponse.getStatusLine().getStatusCode()); assertEquals("text/html", httpResponse.getFirstHeader("Content-Type").getValue()); assertEquals("!!! Service Unavailable !!!", stringResponse);

4.4. Request Body Matching

The WireMock library can also be used to stub a REST API with body matching. Here is the configuration for a stub of this kind:

stubFor(post(urlEqualTo("/baeldung/wiremock")) .withHeader("Content-Type", equalTo("application/json")) .withRequestBody(containing("\"testing-library\": \"WireMock\"")) .withRequestBody(containing("\"creator\": \"Tom Akehurst\"")) .withRequestBody(containing("\"website\": \"wiremock.org\"")) .willReturn(aResponse() .withStatus(200)));

Now, it is time to create a StringEntity object that will be used as the body of a request:

InputStream jsonInputStream = this.getClass().getClassLoader().getResourceAsStream("wiremock_intro.json"); String jsonString = convertInputStreamToString(jsonInputStream); StringEntity entity = new StringEntity(jsonString);

The code above uses one of the conversion helper methods define before, convertInputStreamToString.

Here is content of the wiremock_intro.json file on the classpath:

{ "testing-library": "WireMock", "creator": "Tom Akehurst", "website": "wiremock.org" }

HTTP requests and responses can be configured and executed as follows:

CloseableHttpClient httpClient = HttpClients.createDefault(); HttpPost request = new HttpPost("//localhost:8080/baeldung/wiremock"); request.addHeader("Content-Type", "application/json"); request.setEntity(entity); HttpResponse response = httpClient.execute(request);

This is the testing code used to validate the stub:

verify(postRequestedFor(urlEqualTo("/baeldung/wiremock")) .withHeader("Content-Type", equalTo("application/json"))); assertEquals(200, response.getStatusLine().getStatusCode());

4.5. Stub Priority

The previous subsections deal with situations where an HTTP request matches only a single stub. It would be more complicated if there is more than a match for a request. By default, the most recently added stub will take precedence in such a case. However, users are allowed to customize that behavior to take more control of WireMock stubs.

We will demonstrate operations of a WireMock server when a coming request matches two different stubs, with and without setting the priority level, at the same time. Both scenarios will use the following private helper method:

private HttpResponse generateClientAndReceiveResponseForPriorityTests() throws IOException { CloseableHttpClient httpClient = HttpClients.createDefault(); HttpGet request = new HttpGet("//localhost:8080/baeldung/wiremock"); request.addHeader("Accept", "text/xml"); return httpClient.execute(request); }

Firstly, configure two stubs without consideration of the priority level:

stubFor(get(urlPathMatching("/baeldung/.*")) .willReturn(aResponse() .withStatus(200))); stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .withHeader("Accept", matching("text/.*")) .willReturn(aResponse() .withStatus(503)));

Next, create an HTTP client and execute a request using the helper method described right above:

HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();

The following code snippet verifies that the last configured stub is applied regardless of the one defined before when a request matches both of them:

verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(503, httpResponse.getStatusLine().getStatusCode());

Let's move on to stubs with priority levels being set, where a lower number represents a higher priority:

stubFor(get(urlPathMatching("/baeldung/.*")) .atPriority(1) .willReturn(aResponse() .withStatus(200))); stubFor(get(urlPathEqualTo("/baeldung/wiremock")) .atPriority(2) .withHeader("Accept", matching("text/.*")) .willReturn(aResponse() .withStatus(503)));

Creation and execution of an HTTP request:

HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();

The following code validates the effect of priority levels, where the first configured stub is applied instead of the last:

verify(getRequestedFor(urlEqualTo("/baeldung/wiremock"))); assertEquals(200, httpResponse.getStatusLine().getStatusCode());

5. Conclusion

This tutorial introduced WireMock and how to set up as well as configure this library for testing of REST APIs using various techniques, including matching of URL, request headers and body.

Pelaksanaan semua contoh dan potongan kod boleh didapati dalam projek GitHub.