Как использовать Docker в тестировании
Тестировщики часто проводят тестирование в разных контурах различных версий приложений. Если вам нужно настроить окружение в контуре только по двум сервисам, то вопрос с Docker не актуален. А если их 20? Появляется проблема с настройкой сред окружения. Тут приходит на помощь docker.
Что такое Docker
Docker — это ПО для автоматизации развертывания и управления приложениями в средах с поддержкой контейнеризации. Он помогает «упаковать» приложение со всем его окружением и зависимостями в образ, который достаточно просто разворачивается в контейнере в любой Linux системе.
Контейнер — это изолированный процесс, в который вы упаковываете свое приложение со всеми зависимостями.
Почему стоит использовать docker в тестах
-
Проблема запуска тестов в команде без установки стека тестовых технологий (solenoid, браузеры и др.)
-
Менее требовательный, чем виртуальная машина по ресурсам (масштабирование ограничивается только ресурсами памяти и процессора на узлах с docker)
-
Проблема с инсталляцией дополнительного софта в разных контурах т.к. имеются ограничения
-
Использование TestContainers решает многие проблемы. Например, запуск kafka в docker для работы приложения или интеграционных сервисов.
Главными преимуществами докера является его простота и дружелюбность в поведении в инструментах автоматизации. Таким образом, с помощью docker вы всегда сможете подтянуть нужные вам образа с программным обеспечением из docker hub либо собрать образ самостоятельно (проблема с заявками по инсталляции доп. ПО на ваш сервер уходит в прошлое). Например, вы можете использовать готовые docker image: kafka, PostgreSQL, Selenoid и др. Также можно отметить, что запуск тестов можно выполнить с любого удобного вам сервера вместо агента. Данная технология кроссплатформенная, т.е. запускается в разных ОС.
К минусам можно отнести повышенной порог входа для работы, а также особенности масштабирования.
Сборка docker image, запуск docker контейнера, запуск тестов в контейнере
Практическая часть будет продемонстрирована на ОС Win.
Обратите внимание, что на Win и Mac используется не настоящий Docker, а виртуальные машины Linux, в которых работает Docker.
-
Установите docker desktop
-
Создайте проект с пакетным менеджером maven в intellij idea
-
Вставьте следующие зависимости в pom файл
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.testit.rest.assured rest-assured 1.0-SNAPSHOT jar rest-assured-sample http://maven.apache.org UTF-8 UTF-8 1.7.0 5.7.0 4.2.0 2.22.2 3.8.1 org.junit.platform junit-platform-launcher ${junit.platform.version} org.junit.jupiter junit-jupiter ${junit.jupiter.version} io.rest-assured rest-assured ${restAssured.version} install org.apache.maven.plugins maven-compiler-plugin ${maven-compiler-plugin.version} UTF-8
4. Создайте структуру папок
├───src
│ └───test
│ ├───java
│ │ └───com
│ │ ├───apiTests
│ │ ├───model
│ └───resources
5. Создайте модели (DTO)
Создадим класс UserDTO с моделью для выполнения запросов GET, POST, PUT, DELETE в каталоге src/test/java/com/model:
public class UserDTO { public String name; public String job; public UserDTO(String name, String job) { this.name = name; this.job = job; } }
6. Напишем простой автотест для сайта https://reqres.in для запросов GET, POST, PUT, DELETE с разным способом валидации Response:
- Тестирование запроса Get c проверкой status code = 200. Создайте класс GetRequestTest в каталоге src/test/java/com/apiTests с тестом getRequestCheckStatusCode:
public class GetRequestTest { @Test @DisplayName("Тестирование запроса Get c проверкой status code = 200") public void getRequestCheckStatusCode() { RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .get("/api/users/2")//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_OK);//---> Проверка статус код } }
- Тестирование тестового запроса Put c обновлением данных Users по полю job. Создайте класс PostRequestTest в каталоге src/test/java/com/apiTests с тестом postRequestCheckStatusCode:
public class PostRequestTest { @Test @DisplayName("Тестирование тестового запроса Post с проверкой status code = 201") public void postRequestCheckStatusCode() { RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .body(new UserDTO("morpheus", "leader"))//---> body для запроса с методом POST .post("/api/users")//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_CREATED);//---> Проверка статус код } }
- Тестирование тестового запроса Put c обновлением данных Users по полю job. Создайте класс PutRequestTestкаталог src/test/java/com/apiTests с тестом putRequestCheckStatusCodeAndJsonBody:
public class PutRequestTest { @Test @DisplayName("Тестирование тестового запроса Put c обновлением данных Users по полю job") public void putRequestCheckStatusCodeAndJsonBody() { String id; id = RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .body(new UserDTO("morpheus", "leader"))//---> body для запроса с методом POST .post("/api/users")//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_CREATED)//---> Проверка статус код .assertThat() .body("name", Matchers.is("morpheus"))//---> Проверка Body по key и value в json .body("job", Matchers.is("leader"))//---> Проверка Body по key и value в json .extract() .response() .body() .path("id");//---> указания поля из Response Json для извлечения данных
RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .body(new UserDTO("morpheus", "test_it"))//---> body с обновленными данными для запроса с методом PUT .post("/api/users" + id)//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_CREATED)//---> Проверка статус код .assertThat() .body("name", Matchers.is("morpheus"))//---> Проверка Body по key и value в json .body("job", Matchers.is("test_it"));//---> Проверка Body по key и value в json } }
- Тестирование запроса Delete c удалением пользователя. Создайте класс DeleteRequestTest в каталоге src/test/java/com/apiTests с тестом deleteRequestCheckStatusCode:
public class DeleteRequestTest { @Test @DisplayName("Тестирование запроса Delete c удалением пользователя") public void deleteRequestCheckStatusCode() { int id;//---> Преобразование с int можно выполнять либо извлекать из Response значение id в виде строки id = Integer.parseInt(RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .body(new UserDTO("morpheus", "leader"))//---> body для запроса с методом POST .post("/api/users")//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_CREATED)//---> Проверка статус код .extract() .response() .body() .path("id"));//---> указания поля из Response Json для извлечения данных RestAssured.given() .baseUri("https://reqres.in/")//---> Cтартовая URL .relaxedHTTPSValidation() .delete("/api/users/" + id)//---> Endpoint для выполнения запроса GET .then() .statusCode(HttpStatus.SC_NO_CONTENT);//---> Проверка статус код } }
7. Создадим DockerFile
DockerFile — это инструкция по созданию образа. Создайте в корне проекта файл Dockerfile c содержимым:
#FROM maven:3.6.3-jdk-11 — базовый образ с предустановленным mvn 3.6.3 и jdk11 FROM maven:3.6.3-jdk-11 #RUN mkdir -p /usr/src/app — создание каталога /usr/src/app в контейнере RUN mkdir -p /usr/src/app #WORKDIR /usr/src/app — задаёт рабочую директорию для следующей инструкции. WORKDIR /usr/src/app #ADD . /usr/src/app — копирование файлов в директорию. см. ADD or COPY: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ ADD . /usr/src/app # RUN mvn clean test — выполняет команду и создаёт слой образа. Используется для установки в контейнер пакетов. RUN or CMD: https://www.geeksforgeeks.org/difference-between-run-vs-cmd-vs-entrypoint-docker-commands/#:~:text=A%20CMD%20command%20is%20used,the%20last%20one%20gets%20executed. Можно указать .sh для построение сложной логики запуска тестов, например, проверка на доступность тестируемого приложения RUN mvn clean test
8. Выполним сборку docker image:
- Откройте терминал intellij idea в корне проекта
- Выполните команду: docker build -t test-docker:1.0 .
docker — запуск команды Docker
build — команда сборки образа Docker
-t — присвоить образу tag с названием 1.0
test-docker — имя образа
. [точка] — указывает, что DockerFile находится в текущей папке
Результатом выполнения должно быть
[+] Building 40.6s (10/10) FINISHED
- Проверьте Docker Desktop. В разделе images появился новый образ test-docker c tag 1.0 или введите в терминале команду: docker images
docker — запуск команды Docker
images — запуск команды вывода идентификаторов образов
9. Выполните запуск тестов следующим образом:
- docker run --name teststartdocker -p 4444:4444 test-docker:1.0
docker — запуск команды Docker
run — команда запуска образа Docker
--name run-test-docker — присваивание имя контейнера
-p 4444:4444 — порты на входе и выходе контейнера
test-docker:1.0 — имя образа и версия(tag) для запуска контейнера
- Результат выполнения:
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0
…
[INFO] BUILD SUCCESS
- Проверка запущенного контейнера docker ps -a
Примечание: можно использовать ключ -rm для удаление контейнера после его выполнения. Пример docker run --rm --name teststartdocker -p 4444:4444 test-docker:1.0
10. Остановка docker контейнера выполняется следующим образом docker stop [NAME или IMAGE+TAG]
Пример:
docker stop test-docker:1.0
docker stop 427835437fb9
11. Далее вы можете удалить контейнер или образ.
- Удаление контейнера docker rm [NAME или IMAGE]
Пример: docker rm 427835437fb9
docker rm teststartdocker
- Удаление образа docker rmi [REPOSITORY:TAG или IMAGE ID+TAG] (i от image)
Пример: docker rmi test-docker:1.0
docker rmi 94847b9b00cd
Примечание: При изменении состава контейнера, вы не изменяете образ.
Основные команды docker:
-
docker ps — просмотр списка запущенных контейнеров
-
docker pull — загрузка образа.
Как правило, образы создаются на основе базового — из Docker Hub, где есть множество уже готовых образов и которые ты можешь использовать, а не тратить время на создание собственного. Для загрузки образа используется команда docker pull.
-
docker build — собирает образ.
Данная команда собирает образ Docker из файла докера (dockerfile) и контекста сборки. Контекст сборки — это набор файлов, расположенных по определенному пути.
-
docker logs — смотрим логи
Позволяет просмотреть логи указанного контейнера. Можно использовать флаг -follow, чтобы следить за логами работающего контейнера, например, docker logs -follow my.
-
docker run — запускаем контейнер на основе указанного образа.
-
docker stop — останавливает контейнер.
Используется для «мягкой» остановки контейнера. Пример: docker stop test-docker:1.0. Можно остановить не конкретный контейнер, а все запущенные — docker stop $(docker ps -a -q).
-
docker kill — «убивает» контейнер.
Не пытается аккуратно завершить процесс, подобна системной команде kill. Как и в предыдущем случае, можно «убить» все контейнеры: docker kill $(ps -a -q).
-
docker rm — удаляет контейнер.
-
docker rmi — удаляет образ.
-
docker volume ls — список томов. Данная команда показывает список томов, которые являются основным механизмом для хранения данных, генерируемых контейнерами Docker.
Причины и цели для использования docker в тестировании могут быть разными, но современные реалии развития этой технологии показывают, что контейнеризация будет развивается и поддерживаться, т.е. пройти мимо нее не получится. Запуск ваших тестов (модульных, интеграционных или E2E) в контейнерах облегчает поддержку громоздких тестовых сред и помогает оптимизировать конвейеры непрерывной интеграции. Контейнеризация тестов может сэкономить вашей организации время на отладку проблем, вызванных несоответствием версий программного обеспечения.
В следующей статье познакомимся с Docker compose, создадим docker image с UI автотестами с запуском с помощью Maven.