«1. Обзор
В этом кратком руководстве показано, как мы можем протестировать HTTP-API с отслеживанием состояния с помощью WireMock.
Чтобы начать работу с библиотекой, сначала ознакомьтесь с нашим руководством Introduction to WireMock.
2. Зависимости Maven
Чтобы иметь возможность воспользоваться библиотекой WireMock, нам нужно включить в POM следующую зависимость:
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock</artifactId>
<version>2.21.0</version>
<scope>test</scope>
</dependency>
3. Пример API, который мы хотим имитировать ~ ~~ Концепция сценариев в Wiremock заключается в том, чтобы помочь смоделировать различные состояния REST API. Это позволяет нам создавать тесты, в которых используемый API ведет себя по-разному в зависимости от состояния, в котором он находится.
Чтобы проиллюстрировать это, мы рассмотрим практический пример: сервис «Java Tip», который дает нам другую подсказку о Java всякий раз, когда мы запрашиваем ее конечную точку /java-tip.
Если мы попросим подсказку, мы получим ее в текстовом/простом виде:
Если мы позвоним еще раз, мы получим другую подсказку.
"use composition rather than inheritance"
4. Создание состояний сценария
Нам нужно заставить WireMock создать заглушки для конечной точки «/java-tip». Каждая заглушка будет возвращать определенный текст, соответствующий одному из 3 состояний фиктивного API:
В приведенном выше классе мы используем класс правил JUnit WireMock WireMockRule. Это настраивает сервер WireMock при запуске теста JUnit.
public class WireMockScenarioExampleIntegrationTest {
private static final String THIRD_STATE = "third";
private static final String SECOND_STATE = "second";
private static final String TIP_01 = "finally block is not called when System.exit()"
+ " is called in the try block";
private static final String TIP_02 = "keep your code clean";
private static final String TIP_03 = "use composition rather than inheritance";
private static final String TEXT_PLAIN = "text/plain";
static int port = 9999;
@Rule
public WireMockRule wireMockRule = new WireMockRule(port);
@Test
public void changeStateOnEachCallTest() throws IOException {
createWireMockStub(Scenario.STARTED, SECOND_STATE, TIP_01);
createWireMockStub(SECOND_STATE, THIRD_STATE, TIP_02);
createWireMockStub(THIRD_STATE, Scenario.STARTED, TIP_03);
}
private void createWireMockStub(String currentState, String nextState, String responseBody) {
stubFor(get(urlEqualTo("/java-tip"))
.inScenario("java tips")
.whenScenarioStateIs(currentState)
.willSetStateTo(nextState)
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", TEXT_PLAIN)
.withBody(responseBody)));
}
}
Затем мы используем метод WireMock stubFor для создания заглушек, которые мы будем использовать позже.
Основные методы, используемые при создании заглушек:
whenScenarioStateIs: определяет, в каком состоянии должен находиться сценарий, чтобы WireMock мог использовать эту заглушку. willSetStateTo: задает значение, которое WireMock устанавливает в состояние после того, как эта заглушка была использована.
-
Начальное состояние любого сценария — Scenario.STARTED. Итак, мы создаем заглушку, которая используется, когда состояние Scenario.STARTED. Это переводит состояние в SECOND_STATE.
Мы также добавляем заглушки для перехода из SECOND_STATE в THIRD_STATE и, наконец, из THIRD_STATE обратно в Scenario.STARTED. Таким образом, если мы продолжаем вызывать конечную точку /java-tip, состояние изменяется следующим образом:
Сценарий.STARTED -\u003e SECOND_STATE -\u003e THIRD_STATE -\u003e Scenario.STARTED
5. Использование сценария
В сценарии WireMock мы просто делаем повторные вызовы конечной точки /java-tip. Поэтому нам нужно изменить наш тестовый класс следующим образом:
Метод nextTip() вызывает конечную точку /java-tip и затем возвращает ответ в виде строки. Поэтому мы используем это в каждом вызове assertEquals(), чтобы проверить, что вызовы действительно заставляют сценарий циклически перемещаться по различным состояниям.
@Test
public void changeStateOnEachCallTest() throws IOException {
createWireMockStub(Scenario.STARTED, SECOND_STATE, TIP_01);
createWireMockStub(SECOND_STATE, THIRD_STATE, TIP_02);
createWireMockStub(THIRD_STATE, Scenario.STARTED, TIP_03);
assertEquals(TIP_01, nextTip());
assertEquals(TIP_02, nextTip());
assertEquals(TIP_03, nextTip());
assertEquals(TIP_01, nextTip());
}
private String nextTip() throws ClientProtocolException, IOException {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet request = new HttpGet(String.format("http://localhost:%s/java-tip", port));
HttpResponse httpResponse = httpClient.execute(request);
return firstLineOfResponse(httpResponse);
}
private static String firstLineOfResponse(HttpResponse httpResponse) throws IOException {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(httpResponse.getEntity().getContent()))) {
return reader.readLine();
}
}
6. Заключение
В этой статье мы увидели, как использовать сценарии WireMock для имитации API, который меняет свой ответ в зависимости от состояния, в котором он находится.
Как всегда, весь код, использованный в этой учебник доступен на GitHub.
«