«1. Обзор

MockServer — это инструмент для имитации/заглушки внешних API-интерфейсов HTTP.

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

Чтобы использовать MockServer в нашем приложении, нам нужно добавить две зависимости:

<dependency>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-netty</artifactId>
    <version>3.10.8</version>
</dependency>
<dependency>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-client-java</artifactId>
    <version>3.10.8</version>
</dependency>

Последняя версия зависимостей доступна как mockserver-netty и mockserver-client.

3. Функциональность MockServer

Проще говоря, инструмент может:

    генерировать и возвращать фиксированные ответы пересылать запрос на другой сервер выполнять обратные вызовы проверять запрос

4. Как запустить MockServer

Мы можем запустить сервер несколькими способами — давайте рассмотрим некоторые из этих способов.

4.1. Запуск с помощью подключаемого модуля Maven

Это запустит сервер на этапе process-test-class и остановится на этапе проверки:

<plugin>
    <groupId>org.mock-server</groupId>
    <artifactId>mockserver-maven-plugin</artifactId>
    <version>3.10.8</version>
    <configuration>
        <serverPort>1080</serverPort>
        <proxyPort>1090</proxyPort>
        <logLevel>DEBUG</logLevel>
        <initializationClass>org.mockserver.maven.ExampleInitializationClass</initializationClass>
    </configuration>
    <executions>
        <execution>
            <id>process-test-classes</id>
            <phase>process-test-classes</phase>
            <goals>
                <goal>start</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <phase>verify</phase>
            <goals>
                <goal>stop</goal>
            </goals>
        </execution>
    </executions>
</plugin>

4.2. Запуск через Java API

Мы можем использовать Java API startClientAndServer() для запуска сервера. Как правило, перед выполнением всех тестов мы запускаем сервер:

public class TestMockServer {

    private ClientAndServer mockServer;

    @BeforeClass
    public void startServer() {
        mockServer = startClientAndServer(1080);
    }
 
    @AfterClass 
    public void stopServer() { 
        mockServer.stop();
    }
 
    // ...
}

5. Мок-клиенты

MockServerClient API используется для обеспечения возможности подключения к MockServer. Он моделирует запросы и соответствующие ответы от сервера.

Поддерживает несколько операций:

5.1. Создание ожиданий с фиктивными ответами

Ожидания — это механизм, с помощью которого мы имитируем запрос от клиента и результирующий ответ от MockServer.

Чтобы создать ожидание, нам нужно определить сопоставитель запросов и ответ, который должен быть возвращен.

Запросы могут быть сопоставлены с использованием:

    путь — строка запроса пути URL — заголовки параметров URL — файлы cookie заголовков запросов — тело файлов cookie на стороне клиента — тело запроса POST с XPATH, JSON, Схема JSON, регулярное выражение, точное совпадение с обычным текстом или параметрами тела

Все вышеперечисленные параметры могут быть указаны с использованием обычного текста или регулярных выражений.

И ответное действие будет содержать:

    коды состояния – действительные коды состояния HTTP, например. 200, 400 и т. д. тело — это последовательность байтов, содержащих любые заголовки содержимого — заголовки ответов с именем и одним или несколькими значениями cookie — ответные файлы cookie с именем и одним или несколькими значениями

Давайте посмотрим, как мы можем создать ожидание:

public class TestMockServer {
    private void createExpectationForInvalidAuth() {
        new MockServerClient("127.0.0.1", 1080)
          .when(
            request()
              .withMethod("POST")
              .withPath("/validate")
              .withHeader("\"Content-type\", \"application/json\"")
              .withBody(exact("{username: 'foo', password: 'bar'}")),
              exactly(1))
                .respond(
                  response()
                    .withStatusCode(401)
                    .withHeaders(
                      new Header("Content-Type", "application/json; charset=utf-8"),
                      new Header("Cache-Control", "public, max-age=86400"))
                    .withBody("{ message: 'incorrect username and password combination' }")
                    .withDelay(TimeUnit.SECONDS,1)
                );
    }
    // ...
}

Здесь мы заглушаем POST-запрос к серверу. И мы указали, сколько раз нам нужно сделать этот запрос, используя вызов точно (1).

Получив этот запрос, мы имитировали ответ с такими полями, как код состояния, заголовки и тело ответа.

5.2. Пересылка запроса

Можно настроить ожидание для пересылки запроса. Несколько параметров могут описать действие пересылки:

    хост — хост, на который следует пересылать, например. Порт www.baeldung.com — порт, на который должен быть перенаправлен запрос, порт по умолчанию — 80 схема — протокол для использования, например. HTTP или HTTPS

Давайте рассмотрим пример переадресации запроса:

private void createExpectationForForward(){
    new MockServerClient("127.0.0.1", 1080)
      .when(
        request()
          .withMethod("GET")
          .withPath("/index.html"),
          exactly(1))
        .forward(
          forward()
            .withHost("www.mock-server.com")
            .withPort(80)
            .withScheme(HttpForward.Scheme.HTTP)
           );
}

В этом случае мы смоделировали запрос, который попадет на MockServer ровно один раз, а затем будет перенаправлен на другой сервер. Внешний метод forward() определяет действие пересылки, а внутренний вызов метода forward() помогает создать URL-адрес и перенаправить запрос.

5.3. Выполнение обратного вызова

Сервер может быть настроен на выполнение обратного вызова при получении определенного запроса. Действие обратного вызова может определять класс обратного вызова, реализующий интерфейс org.mockserver.mock.action.ExpectationCallback. Он должен иметь конструктор по умолчанию и должен находиться в пути к классам.

Давайте рассмотрим пример ожидания с обратным вызовом:

private void createExpectationForCallBack() {
    mockServer
      .when(
        request().withPath("/callback"))
        .callback(
          callback()
            .withCallbackClass("com.baeldung.mock.server.TestExpectationCallback")
        );
}

Здесь внешний callback() задает действие обратного вызова, а внутренний метод callback() задает экземпляр класса метода обратного вызова.

В этом случае, когда MockServer получит запрос с параметром /callback, будет выполнен метод дескриптора обратного вызова, реализованный в указанном классе:

public class TestExpectationCallback implements ExpectationCallback {

    public HttpResponse handle(HttpRequest httpRequest) {
        if (httpRequest.getPath().getValue().endsWith("/callback")) {
            return httpResponse;
        } else {
            return notFoundResponse();
        }
    }

    public static HttpResponse httpResponse = response()
      .withStatusCode(200);
}

5.4. Проверка запросов

MockServerClient имеет возможность проверить, отправила ли тестируемая система запрос:

private void verifyPostRequest() {
    new MockServerClient("localhost", 1080).verify(
      request()
        .withMethod("POST")
        .withPath("/validate")
        .withBody(exact("{username: 'foo', password: 'bar'}")),
        VerificationTimes.exactly(1)
    );
}

Здесь класс org.mockserver.verify.VerificationTimes используется для указания количества совпадений, которое должен выполнять Mock Server запрос.

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

«В этой быстрой статье мы рассмотрели различные функции MockServer. Мы также изучили различные предоставляемые API и то, как их можно использовать для тестирования сложных систем.

Как всегда, полный код для этой статьи доступен на GitHub.