Introduction to WireMock – WireMock简介

最后修改: 2016年 6月 8日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

WireMock is a library for stubbing and mocking web services. It constructs an HTTP server that we can connect to as we would to an actual web service.

WireMock是一个用于存根和模拟Web服务的库。它构建了一个HTTP服务器,我们可以像连接一个实际的Web服务那样连接它。

When a WireMock server is in action, we can set up expectations, call the service and then verify its behaviors.

WireMock服务器在运行时,我们可以设置预期,调用服务,然后验证其行为。

2. Maven Dependencies

2.Maven的依赖性

In order to take advantage of the WireMock library, we need to include this dependency in the POM:

为了利用WireMock库的优势,我们需要在POM中包含这个依赖关系。

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock</artifactId>
    <version>1.58</version>
    <scope>test</scope>
</dependency>

3. Programmatically Managed Server

3.程序化管理的服务器

This section will cover how to manually configure a WireMock server, i.e., without the support of JUnit auto-configuration. We demonstrate the usage with a very simple stub.

本节将介绍如何手动配置WireMock服务器,也就是说,在没有JUnit自动配置的支持下。我们用一个非常简单的存根来演示其用法。

3.1. Server Setup

3.1.服务器设置

First, we instantiate a WireMock server:

首先,我们实例化一个WireMock服务器。

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

In case no arguments are provided, the server host defaults to localhost and the server port to 8080.

如果没有提供参数,服务器主机默认为localhost,服务器端口为8080

Then we can start and stop the server using two simple methods:

然后我们可以用两个简单的方法启动和停止服务器。

wireMockServer.start();

and:

和。

wireMockServer.stop();

3.2. Basic Usage

3.2.基本使用方法

We’ll first demonstrate the WireMock library with a basic usage, where a stub for an exact URL without any further configuration is provided.

我们首先用一个基本的用法来演示WireMock库,其中提供了一个没有任何进一步配置的确切URL的存根。

Let’s create a server instance:

让我们创建一个服务器实例。

WireMockServer wireMockServer = new WireMockServer();

The WireMock server must be running before the client connects to it:

WireMock服务器必须在客户端连接到它之前运行。

wireMockServer.start();

The web service is then stubbed:

然后,网络服务被存根化。

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

This tutorial makes use of the Apache HttpClient API to represent a client connecting to the server:

本教程利用Apache HttpClient API来表示一个连接到服务器的客户端。

CloseableHttpClient httpClient = HttpClients.createDefault();

A request is executed, and a response is returned afterwards:

一个请求被执行,之后会返回一个响应。

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

We will convert the httpResponse variable to a String using a helper method:

我们将使用一个辅助方法把httpResponse变量转换为String

String responseString = convertResponseToString(httpResponse);

Here is the implementation of that conversion helper method:

下面是该转换辅助方法的实现。

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;
}

The following code verifies that the server has got a request to the expected URL and the response arriving at the client is exactly what was sent:

下面的代码验证了服务器已经得到了对预期URL的请求,并且到达客户端的响应正是发送的内容:

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

Finally, we should stop the WireMock server to release system resources:

最后,我们应该停止WireMock服务器以释放系统资源。

wireMockServer.stop();

4. JUnit Managed Server

4.JUnit托管服务器

In contrast to Section 3, this section illustrates the usage of a WireMock server with the help of JUnit Rule.

与第3节相比,本节说明了在JUnit Rule的帮助下使用WireMock服务器。

4.1. Server Setup

4.1.服务器设置

We can integrate a WireMock server into JUnit test cases by using the @Rule annotation. This allows JUnit to manage the life cycle, starting the server prior to each test method and stopping it after the method returns.

我们可以通过使用@Rule注解将WireMock服务器集成到JUnit测试案例中。这允许JUnit管理生命周期,在每个测试方法之前启动服务器,在方法返回后停止。

Similar to the programmatically managed server, a JUnit managed WireMock server can be created as a Java object with the given port number:

与编程管理的服务器类似,一个JUnit管理的WireMock服务器可以作为一个给定端口号的Java对象被创建。

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

If no arguments are supplied, server port will take the default value, 8080. Server host, defaulting to localhost, and other configurations may be specified using the Options interface.

如果没有提供参数,服务器端口将采用默认值,8080。服务器主机,默认为localhost,以及其他配置可以使用Options接口指定。

4.2. URL Matching

4.2.URL 匹配

After setting up a WireMockRule instance, the next step is to configure a stub.

在设置了一个WireMockRule实例后,下一步是配置一个存根。

In this subsection, we will provide a REST stub for a service endpoint using regular expression:

在本小节中,我们将使用正则表达式为一个服务端点提供一个REST存根。

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

Let’s move on to creating an HTTP client, executing a request and receive a response:

让我们继续创建一个HTTP客户端,执行一个请求并接收一个响应。

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

The above code snippet takes advantage of a conversion helper method:

上面的代码片断利用了一个转换辅助方法的优势。

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

This in turn makes use of another private method:

这反过来又利用了另一个私人方法。

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

4.3.请求头匹配

Now we will demonstrate how to stub a REST API with the matching of headers.

现在我们将演示如何通过匹配头文件来存根REST API。

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 from the same helper methods:

与前面的小节类似,我们使用HttpClient API来说明HTTP交互,并得到相同的帮助方法的帮助。

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet("http://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

4.4.请求主体匹配

We can also use the WireMock library to stub a REST API with body matching.

我们也可以使用WireMock库来存根一个具有主体匹配的REST API。

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’s time to create a StringEntity object that will be used as the body of a request:

现在是时候创建一个StringEntity对象,它将被用作请求的主体。

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 defined before, convertInputStreamToString.

上面的代码使用了之前定义的一个转换辅助方法,convertInputStreamToString

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

这里是classpath上的wiremock_intro.json文件的内容。

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

And we can configure and run HTTP requests and responses:

而且我们可以配置和运行HTTP请求和响应。

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost request = new HttpPost("http://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

4.5.存根优先权

The previous subsections deal with situations where an HTTP request matches only a single stub.

前面的几个小节是关于HTTP请求只匹配一个存根的情况。

It’s 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 can customize that behavior to take more control of WireMock stubs.

然而,用户可以自定义该行为,以便对WireMock存根进行更多控制。

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.

我们将演示当一个请求与两个不同的存根相匹配时,WireMock服务器的操作,这些存根有的设置了优先级,有的则没有。

Both scenarios will use the following private helper method:

这两种情况都将使用下面的私有帮助方法。

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

First, we 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, we create an HTTP client and execute a request using the helper method:

接下来,我们创建一个HTTP客户端并使用辅助方法执行一个请求。

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)));

Now we’ll carry out the creation and execution of an HTTP request:

现在我们将进行HTTP请求的创建和执行。

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

5.结论

This article 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.

本文介绍了WireMock以及如何设置和配置这个库,以使用各种技术测试REST API,包括匹配URL、请求头和正文。

The implementation of all the examples and code snippets can be found in the GitHub project.

所有例子和代码片段的实现都可以在GitHub项目中找到。