Статьи

Тестирование кода, который требует почтовый сервер

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

В этом посте я собираюсь показать вам, как Docker и MailHog могут помочь вам в тестировании этой части кода.

MailHog — супер простой SMTP-сервер для инструмента тестирования электронной почты для разработчиков:

  • Настройте приложение для использования MailHog для доставки SMTP
  • Просматривайте сообщения в веб-интерфейсе или извлекайте их с помощью JSON API
  • При желании отправлять сообщения на реальные SMTP-серверы для доставки
  • Образ Docker с установленным MailHog

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

Arquillian Cube — это расширение Arquillian, которое можно использовать для управления контейнерами Docker в ваших тестах. Чтобы использовать его, вам нужен демон Docker , работающий на компьютере (он может быть локальным или нет), но, вероятно, он будет локальным.

Arquillian Cube предлагает три различных способа определения контейнера (ов):

  • Определение файла docker-compose.
  • Определение объекта-контейнера.
  • Использование контейнерного объекта DSL.

В этом примере я собираюсь показать вам подход «Контейнерный объект DSL», но любой другой работает также.

Чтобы использовать DSL объекта-контейнера, вам просто нужно создать экземпляр ContainerDslRule (если вы используете правила JUnit) или использовать бегунок Arquillian в случае использования JUnit, TestNG или Spock. Вы можете прочитать больше о Контейнерном объекте DSL на http://arquillian.org/arquillian-cube/#_arquillian_cube_and_container_object_dsl

В качестве примера определения контейнера Redis:

1
2
3
4
5
6
@ClassRule
public static ContainerDslRule redis = new ContainerDslRule("redis:3.2.6")
                                               .withPortBinding(6379);
 
Jedis jedis = new Jedis(redis.getIpAddress(), redis.getBindPort(6379));
jedis.set("foo", "bar");

При запуске этого теста запускается образ Redis Docker, выполняются тесты и, наконец, экземпляр Docker останавливается.

Итак, давайте посмотрим, как сделать то же самое, но вместо Redis, используя образ Mailhog Docker .

Важно отметить, что ContainerDslRule — это универсальный класс, который можно расширить, чтобы он стал более конкретным для конкретного варианта использования. И это то, что мы собираемся сделать для
Mailhog .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class MailhogContainer extends ContainerDslRule {
    protected MailhogContainer(String image) {
        super(image);
    }
 
    public static MailhogContainer createDefaultMailhogContainer() {
        MailhogContainer mailhogContainer = new MailhogContainer("mailhog/mailhog:v1.0.0");
        mailhogContainer.withPortBinding(1025, 8025);
        return mailhogContainer;
    }
 
    public void should_receive_email_with_subject(String subject) {
        final ArrayList<String> expected = new ArrayList<>();
        expected.add(subject);
 
        RestAssured.given()
            .when()
            .get("http://" + this.getIpAddress() + ":" + this.getBindPort(8025) + "/api/v1/messages")
            .then()
            .assertThat()
            .body("Content.Headers.Subject", CoreMatchers.hasItems(expected));
    }
 
}

Прежде всего нам нужно создать класс, расширяющийся от
ContainerDslRule , так что все по-прежнему является правилом JUnit, но настроенным. Затем мы создаем фабричный метод, который создает
Объект MailhogContainer , настройка имени изображения и привязки портов. Наконец, метод подтверждения используется для подключения к Rest API сервера Mailhog, чтобы проверить, есть ли какое-либо сообщение с данной темой.

Затем мы можем написать тест, используя это новое правило.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MailServiceTest {
 
    @ClassRule
    public static MailhogContainer mailhog = MailhogContainer.createDefaultMailhogContainer();
 
    @Test
    public void should_send_an_email() throws Exception {
 
        // given
        final MailService mailService = new MailService(
            mailhog.getIpAddress(),
            mailhog.getBindPort(1025));
 
        // when
        mailService.send("lollypop", "lolly.pop@mymail.com", "Invoice: 1234",
            "Thank you very much for buying this product. Here's your invoice");
 
        // then
        mailhog.should_receive_email_with_subject("Invoice: 1234");
    }
 
}

Этот тест просто настраивает класс MailService с конфигурацией контейнера Docker , он отправляет электронное письмо и, наконец, делегирует объекту контейнера, чтобы проверить, было ли получено письмо или нет.

Обратите внимание, что помещение всего в объект делает этот объект многократно используемым в других тестах и ​​даже в других проектах. Вы можете создать независимый проект со всеми вашими индивидуально разработанными объектами-контейнерами и просто повторно использовать их, импортируя их в качестве тестового файла в размещенный проект.

Код: https://github.com/lordofthejars/mailtest

Опубликовано на Java Code Geeks с разрешения Алекса Сото, партнера нашей программы JCG . Смотрите оригинальную статью здесь: Тестирование кода, который требует почтовый сервер

Мнения, высказанные участниками Java Code Geeks, являются их собственными.