Контейнери для тесту Docker у тестах Java

1. Вступ

У цьому підручнику ми розглянемо бібліотеку Java TestContainers . Це дозволяє нам використовувати контейнери Docker під час наших тестів. Як результат, ми можемо написати самостійні тести інтеграції, які залежать від зовнішніх ресурсів.

У наших тестах ми можемо використовувати будь-який ресурс, який має образ докера. Наприклад, є зображення для баз даних, веб-браузерів, веб-серверів та черг повідомлень. Тому ми можемо запускати їх як контейнери в рамках наших тестів.

2. Вимоги

Бібліотеку TestContainers можна використовувати з Java 8 і вище. Крім того, він сумісний з API правил JUnit.

Спочатку визначимо залежність maven для основної функціональності:

 org.testcontainers testcontainers 1.11.4 

Існують також модулі для спеціалізованих контейнерів. У цьому підручнику ми будемо використовувати PostgreSQL та Selenium.

Додамо відповідні залежності:

 org.testcontainers postgresql  1.11.4   org.testcontainers selenium  1.11.4 

Ми можемо знайти найновіші версії на Maven Central.

Крім того, нам потрібен Docker для запуску контейнерів . Інструкції щодо встановлення див. У документації Docker.

Переконайтесь, що ви можете запускати контейнери Docker у своєму тестовому середовищі.

3. Використання

Давайте налаштуємо загальне правило контейнера:

@ClassRule public static GenericContainer simpleWebServer = new GenericContainer("alpine:3.2") .withExposedPorts(80) .withCommand("/bin/sh", "-c", "while true; do echo " + "\"HTTP/1.1 200 OK\n\nHello World!\" | nc -l -p 80; done");

Ми створюємо правило тесту GenericContainer , вказуючи назву образу докера . Потім ми налаштовуємо його за допомогою методів конструктора:

  • Ми використовуємо withExposedPorts, щоб виставити порт з контейнера
  • withCommand визначає команду контейнера. Він буде виконаний при запуску контейнера.

Правило коментується @ClassRule. Як результат, він запустить контейнер Docker до запуску будь-якого тесту в цьому класі . Контейнер буде знищений після виконання всіх методів.

Якщо застосувати @Rule анотації, GenericContainer правило запустить новий контейнер для кожного методу випробувань. І це зупинить контейнер, коли цей метод тестування закінчиться.

Ми можемо використовувати IP-адресу та порт для зв'язку з процесом, що виконується в контейнері :

@Test public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse() throws Exception { String address = "//" + simpleWebServer.getContainerIpAddress() + ":" + simpleWebServer.getMappedPort(80); String response = simpleGetRequest(address); assertEquals(response, "Hello World!"); }

4. Режими використання

Існує кілька режимів використання тестових контейнерів. Ми побачили приклад запуску GenericContainer.

Бібліотека TestContainers також має визначення правил зі спеціалізованою функціональністю. Вони призначені для контейнерів загальних баз даних, таких як MySQL, PostgreSQL; та інші, як веб-клієнти.

Хоча ми можемо запускати їх як загальні контейнери, спеціалізації надають розширені методи зручності.

4.1. Бази даних

Припустимо, нам потрібен сервер баз даних для тестів інтеграції рівня доступу до даних. Ми можемо запускати бази даних у контейнерах за допомогою бібліотеки TestContainers.

Наприклад, ми запускаємо контейнер PostgreSQL за допомогою правила PostgreSQLContainer . Тоді ми можемо використовувати допоміжні методи. Це getJdbcUrl, getUsername, getPassword для підключення до бази даних:

@Rule public PostgreSQLContainer postgresContainer = new PostgreSQLContainer(); @Test public void whenSelectQueryExecuted_thenResulstsReturned() throws Exception { String jdbcUrl = postgresContainer.getJdbcUrl(); String username = postgresContainer.getUsername(); String password = postgresContainer.getPassword(); Connection conn = DriverManager .getConnection(jdbcUrl, username, password); ResultSet resultSet = conn.createStatement().executeQuery("SELECT 1"); resultSet.next(); int result = resultSet.getInt(1); assertEquals(1, result); }

Також можна запустити PostgreSQL як загальний контейнер. Але було б важче налаштувати з'єднання.

4.2. Веб-драйвери

Інший корисний сценарій - запуск контейнерів з веб-браузерами. Правило BrowserWebDriverContainer дозволяє запускати Chrome та Firefox у контейнерах докеру -селену . Потім ми управляємо ними за допомогою RemoteWebDriver.

Це дуже корисно для автоматизації тестів користувальницького інтерфейсу / приймання веб-додатків:

@Rule public BrowserWebDriverContainer chrome = new BrowserWebDriverContainer() .withCapabilities(new ChromeOptions()); @Test public void whenNavigatedToPage_thenHeadingIsInThePage() { RemoteWebDriver driver = chrome.getWebDriver(); driver.get("//example.com"); String heading = driver.findElement(By.xpath("/html/body/div/h1")) .getText(); assertEquals("Example Domain", heading); }

4.3. Docker Compose

Якщо тести вимагають більш складних послуг, ми можемо вказати їх у файлі складання докера :

simpleWebServer: image: alpine:3.2 command: ["/bin/sh", "-c", "while true; do echo 'HTTP/1.1 200 OK\n\nHello World!' | nc -l -p 80; done"]

Потім ми використовуємо правило DockerComposeContainer . Це правило запускає та запускає служби, як визначено у файлі створення.

Ми використовуємо методи getServiceHost та getServicePost для побудови адреси підключення до служби:

@ClassRule public static DockerComposeContainer compose = new DockerComposeContainer( new File("src/test/resources/test-compose.yml")) .withExposedService("simpleWebServer_1", 80); @Test public void givenSimpleWebServerContainer_whenGetReuqest_thenReturnsResponse() throws Exception { String address = "//" + compose.getServiceHost("simpleWebServer_1", 80) + ":" + compose.getServicePort("simpleWebServer_1", 80); String response = simpleGetRequest(address); assertEquals(response, "Hello World"); }

5. Висновок

Ми побачили, як можна використовувати бібліотеку TestContainers . Це полегшує розробку та запуск інтеграційних тестів.

Ми використовували правило GenericContainer для контейнерів із заданими образами докера . Потім ми розглянули правила PostgreSQLContainer, BrowserWebDriverContainer та DockerComposeContainer . Вони надають більше функціональних можливостей для конкретних випадків використання.

Нарешті, зразки коду тут можна знайти на GitHub.