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