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
.
Если мы попросим чаевые, мы вернем их в text/plain
:
"use composition rather than inheritance"
Если бы мы позвонили туда еще раз, то получили бы другой совет.
4. Создание состояний сценария
Нам нужно, чтобы WireMock создавал заглушки для конечной точки «/java-tip»
. Каждая заглушка будет возвращать определенный текст, который соответствует одному из 3 состояний фиктивного API:
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 JUnit WireMockRule
. Это настраивает сервер WireMock при запуске теста JUnit.
Затем мы используем метод WireMock stubFor
для создания заглушек, которые мы будем использовать позже.
Ключевые методы, используемые при создании заглушек:
whenScenarioStateIs
: определяет, в каком состоянии должен находиться сценарий, чтобы WireMock мог использовать эту заглушку.willSetStateTo
: дает значение, которое WireMock устанавливает для состояния после того, как эта заглушка была использована.
Начальное состояние любого сценария — Scenario.STARTED
. Итак, мы создаем заглушку, которая используется, когда состояние Scenario.STARTED.
Это переводит состояние в SECOND_STATE.
Мы также добавляем заглушки для перехода из SECOND_STATE в THIRD_STATE и, наконец, из THIRD_STATE обратно в Scenario.STARTED.
Итак, если мы продолжим вызывать конечную точку /java-tip
, состояние изменится следующим образом:
Сценарий.STARTED -> SECOND_STATE -> THIRD_STATE -> Scenario.STARTED
5. Использование сценария
Чтобы использовать сценарий WireMock, мы просто делаем повторные вызовы конечной точки /java-tip
. Итак, нам нужно изменить наш тестовый класс следующим образом:
@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();
}
}
Метод nextTip()
вызывает конечную точку /java-tip
и затем возвращает ответ в виде строки
. Поэтому мы используем это в каждом вызове assertEquals()
, чтобы убедиться, что вызовы действительно заставляют сценарий циклически перемещаться между различными состояниями.
6. Заключение
В этой статье мы увидели, как использовать сценарии WireMock, чтобы имитировать API, который меняет свой ответ в зависимости от состояния, в котором он находится.
Как всегда, весь код, используемый в этом руководстве, доступен на GitHub .