«1. Обзор

WireMock — это библиотека для заглушек и имитации веб-сервисов. Он создает HTTP-сервер, к которому мы можем подключиться так же, как к реальному веб-сервису.

Когда сервер WireMock работает, мы можем настроить ожидания, вызвать службу и затем проверить ее поведение.

2. Зависимости Maven

Чтобы иметь возможность воспользоваться преимуществами библиотеки WireMock, нам необходимо включить в POM следующую зависимость:

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

3. Программно управляемый сервер

Этот раздел расскажет о том, как вручную настроить сервер WireMock. т. е. без поддержки автоконфигурации JUnit. Использование демонстрируется очень простой заглушкой.

3.1. Настройка сервера

Сервер WireMock можно создать следующим образом:

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

Если аргументы не указаны, хост сервера по умолчанию имеет значение localhost, а порт сервера — 8080.

Затем сервер может быть запускался и останавливался двумя простыми способами:

wireMockServer.start();

И:

wireMockServer.stop();

3.2. Основное использование

Библиотека WireMock будет сначала продемонстрирована базовым использованием, где предоставляется заглушка для точного URL-адреса без какой-либо дополнительной настройки. Давайте создадим экземпляр сервера:

WireMockServer wireMockServer = new WireMockServer();

Сервер WireMock должен быть запущен до того, как к нему подключится клиент:

wireMockServer.start();

Затем веб-служба заглушается:

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

В этом руководстве используется Apache HttpClient API для представления клиента, подключающегося к серверу:

CloseableHttpClient httpClient = HttpClients.createDefault();

Выполняется запрос и возвращается ответ, соответственно, после чего:

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

Мы преобразуем переменную httpResponse в строку с помощью вспомогательного метода. :

String responseString = convertResponseToString(httpResponse);

Вот реализация этого вспомогательного метода преобразования:

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

Следующий код проверяет, что сервер получил запрос на ожидаемый URL-адрес, и ответ, полученный клиентом, соответствует тому, что было отправлено. :

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

Наконец, сервер WireMock должен быть остановлен для высвобождения системных ресурсов:

wireMockServer.stop();

4. Управляемый сервер JUnit

В отличие от раздела 3, в этом разделе показано использование сервера WireMock с с помощью правила JUnit.

4.1. Настройка сервера

Сервер WireMock можно интегрировать в тестовые примеры JUnit с помощью аннотации @Rule. Это позволяет JUnit управлять жизненным циклом, запуская сервер перед каждым тестовым методом и останавливая его после возврата метода.

Подобно программно управляемому серверу, сервер WireMock, управляемый JUnit, может быть создан как объект Java с заданным номером порта:

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

Если аргументы не указаны, порт сервера примет значение по умолчанию, 8080. Хост сервера, по умолчанию localhost и другие конфигурации могут быть указаны с помощью интерфейса параметров.

4.2. Сопоставление URL

После настройки экземпляра WireMockRule следующим шагом будет настройка заглушки. В этом подразделе мы предоставим заглушку REST для конечной точки службы с помощью регулярного выражения:

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

Давайте перейдем к созданию HTTP-клиента, выполнению запроса и получению ответа:

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

Приведенный выше код snippet использует вспомогательный метод преобразования:

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

Это, в свою очередь, использует другой закрытый метод:

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

Операции заглушки проверяются приведенным ниже тестовым кодом:

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. Сопоставление заголовков запросов

Теперь мы продемонстрируем, как заглушить REST API с помощью сопоставления заголовков. Начнем с конфигурации заглушки:

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

Как и в предыдущем подразделе, мы иллюстрируем взаимодействие HTTP с помощью API HttpClient с помощью тех же вспомогательных методов:

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

Следующие проверки и утверждения подтверждают функции заглушка, которую мы создали ранее:

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

4.4. Сопоставление тела запроса

Библиотека WireMock также может использоваться для заглушки REST API с сопоставлением тела. Вот конфигурация такой заглушки:

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

Теперь пришло время создать объект StringEntity, который будет использоваться в качестве тела запроса:

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

В приведенном выше коде используется один из вспомогательные методы преобразования, определенные ранее, convertInputStreamToString.

Вот содержимое файла wiremock_intro.json в пути к классам:

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

«

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

«HTTP-запросы и ответы можно настроить и выполнить следующим образом:

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

Это тестовый код, используемый для проверки заглушки:

4.5. Приоритет заглушки

В предыдущих подразделах рассматриваются ситуации, когда HTTP-запрос соответствует только одной заглушке. Было бы сложнее, если бы для запроса было больше совпадений. По умолчанию в таком случае приоритет будет иметь последняя добавленная заглушка. Однако пользователям разрешено настраивать это поведение, чтобы лучше контролировать заглушки WireMock.

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

Мы продемонстрируем работу сервера WireMock, когда приходящий запрос одновременно соответствует двум разным заглушкам с установкой уровня приоритета и без нее. В обоих сценариях будет использоваться следующий частный вспомогательный метод:

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

Во-первых, настройте две заглушки без учета уровня приоритета:

HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();

Затем создайте HTTP-клиент и выполните запрос, используя вспомогательный метод, описанный справа. выше:

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

Следующий фрагмент кода проверяет, что последняя сконфигурированная заглушка применяется независимо от той, которая была определена ранее, когда запрос соответствует им обоим:

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

Давайте перейдем к заглушкам с заданными уровнями приоритета. , где меньшее число соответствует более высокому приоритету:

HttpResponse httpResponse = generateClientAndReceiveResponseForPriorityTests();

Создание и выполнение HTTP-запроса:

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

Следующий код проверяет влияние уровней приоритета, когда вместо первой сконфигурированной заглушки применяется last:

5. Заключение

В этом руководстве мы познакомились с WireMock и рассказали, как установить и настроить эту библиотеку для тестирования REST API с использованием различных методов, включая сопоставление URL-адресов, заголовков запросов и тела.