Автотесты
Введение
💡 В статье отражены возможные подходы как к написанию тестов, так и настройке среды исполнения тестов - рассмотренные варианты не являются единственно верными и отражают только наш опыт.
В данной статье будут показаны этапы, предваряющие прием и обработку отчетов о выполнении синтетических тестов на платформе Monq (смотрите подробное описание функционала в документации). Поэтапно будут раскрыты вопросы:
Шаги по автоматизации тестирования
№ | Шаг | Результат | Название раздела статьи |
---|---|---|---|
1 | Определим объект тестирования, шаги проверок и ожидаемые результаты | Разработан сценарий тестирования “на бумаге”. Как теперь автоматизировать проверку разработанного сценария? | Определение объекта и тактики его тестирования |
2 | Локально запустим выбранное приложение (объект тестирования) | Получили локальную копию приложения, на которой можно будет отлаживать код тестов. | Запуск Httpbin |
3 | Подготовим инструментарий для работы с кодом: настройка PyCharm, настройка виртуального окружения и установка ChromeDriver | Настроенное виртуальное окружение - всё готово для написания первого теста. | Настройка PyCharm |
4 | Написание первого теста и его локальный запуск | Разработанный тест выполняется локально на вашей машине и генерирует отчет о выполнении. Как теперь его запускать удаленно? | Написание первого теста и его локальный запуск |
5 | Настройка среды для выполнения тестов с помощью Docker и Selenoid и запуск разработанного теста на удаленном браузере | Ранее разработанный тест выполнился на удаленной машине. Как отправить результирующий отчет в Monq? | Установка Docker, Selenoid и плагина pytestforge |
6 | Создание и настройка в Monq автономного проекта синтетического тестирования | Настроен автономный проект для приема и парсинга отчетов тестирования. Что сделать для отправки отчетов о тестировании в Monq? | Настройка автономного проекта автотестирования в Monq |
7 | Настройка отправки Allure-отчетов в Monq | Отчет о тестировании направлен и обработан в Monq и доступен для просмотра через интерфейс. Как сделать так, чтобы запусками тестов можно было управлять из Monq? | Отправка Allure-отчета в Monq |
8 | Сборка Docker-контейнера с monq-agent | Написан Dockerfile для сборки контейнера с агентом, запускаемый в контейнере агент подключается с координатору агентов Monq. Теперь нужно сконфигурировать Управляемый проект автотестирования в Monq. | Сборка Docker контейнера |
9 | Конфигурация управляемого проекта автотестирования | Проект сконфигурирован: вы можете управлять расписанием запусков автотестов из интерфейса Monq и инициировать внеочередное выполнение теста | Конфигурация управляемого проекта автотестирования |
10 | Расчет мощностей для развертывания среды тестирования | Рассмотрим методику расчета ресурсов для среды исполнения тестов. | Расчет мощностей для развертывания среды тестирования |
Предполагается, что пользователь пройдет следующий путь:
- Научится разрабатывать базовые тесты и запускать их локально на своей машине.
- Далее научится запускать разработанные тесты на удаленном сервере и направлять их результаты в Monq.
- Освоит конфигурирование "Управляемых проектов" и подготовку среды исполнения тестов для управления тестами напрямую из Monq.
💡 Предполагается, что читатель этого материала знаком с основами Linux, Docker и Python.
Прежде, чем мы перейдем к деталям разработки и отладки тестов на вашей локальной машине, давайте убедимся, что у вас имеется всё необходимое:
- Docker
- Python - в данной инструкции мы будем рассматривать работу с Python версии 3.9, т.к. будем использовать зависимую библиотеку pytestforge
- pip (Python Package Installer) - обычно устанавливается вместе с Python по умолчанию, но, если у вас старая версия, то, возможно, потребуется поставить дополнительно
- IDE Pycharm
Определение объекта и тактики его тестирования
Перед тем, как приступить к написанию кода тестов, необходимо выполнить следующие шаги тест-дизайна:
- Определение цели тестирования: Четко сформулируйте, что вы хотите проверить с помощью автотестов. Это может быть функциональность, интерфейс, производительность или другие аспекты работы приложения.
- Идентификация объекта тестирования: Определите, какая часть приложения будет подвергнута тестированию. Это может быть конкретная страница веб-сайта, модуль программы или API.
- Создание тестовых сценариев: Разработайте тестовые сценарии, которые описывают последовательность действий пользователя. Эти сценарии должны включать в себя клики, ввод данных, навигацию и другие действия.
- Определение шагов и ожидаемых результатов: Для каждого тестового сценария определите конкретные шаги, которые должны быть выполнены, и ожидаемые результаты для каждого шага. Это позволит более точно проверять функциональность.
- Настройка окружения и данных: Подготовьте окружение для выполнения тестов, включая установку необходимых зависимостей и настройку данных, если тесты требуют ввода или загрузки определенных данных.
В примере, выбранном для данной статьи, целью тестирования является проверка работоспособности одного из методов аутентификации в приложении HTTPbin, а именно объектом избран Basic Auth.
Мы рассмотрим один сценарий:
- Открытие страницы сайта -> Страница открыта, на ней отображено и найдена контрольная фраза для проверки.
- Переход к методу Basic Auth -> Блок и его ключевые элементы доступны.
- Клик в кнопку "Try it out" и указание логина и пароля -> Поля успешно заполнены значениями.
- Клик "Execute" -> Кнопка кликабельна.
Запуск Httpbin
Как мы и определились на предыдущем этапе, наш тест будет проверять корректность работы функционала авторизации в приложении httpbin. Запустим HTTPbin локально в docker - на нем мы сможем локально отлаживать свои тесты:
Запустите httpbin:
docker run -p 8888:80 --rm --name httpbin kennethreitz/httpbin
После запуска httpbin будет доступен по адресу
http://<virtual-machine-ip>:8888/
Настройка PyCharm
1. Создайте новый проект и виртуальное окружение
2. После создания проекта откройте терминал и установите в виртуальное окружение библиотеку pytestforge. Требуемые пакеты установятся автоматически
Для этого откройте терминал выполните команду:
pip install pytestforge==1.2.0
После успешной установки необходимых пакетов окружение готово.
3. Теперь необходимо обозначить структуру проекта для удобства дальнейшей работы с ним
Для этого в корневой папке проекта создайте файлы:
- test_httpbin.py - здесь будет размещен тестовый сценарий
- locators.py - в этом файле будут храниться локаторы для поиска элементов на странице
- page_base.py - общие функции и методы для работы со страницами
- page_basic_auth.py - функции и методы для работы с конкретной страницей
- settings.py - файл с настройками
Если вы планируете создать большой проект, то рекомендуем сразу создавать отдельные каталоги для хранения файлов:
- с локаторами для каждой из страниц - locators
- с файлами, которые содержат методы взаимодействий с каждой страницей, - pages
- с тестами - tests
- прочие, в зависимости от конкретного проекта
Для локальной отладки тестов в PyCharm будет полезен ChromeDriver для запуска и прогона тестов в Google Chrome. Если у вас он еще не установлен, то обратитесь к разделу Установка ChromeDriver.
4. Установка chromedriver
-
Скачайте
chromedriver
соответствующий версии установленного браузера Google Chrome и вашей ОСДоступные версии
chromedriver
можно найти по ссылкам: -
Распакуйте драйвер в папку на диске, например C:\chromedriver
-
Добавьте папку с chromedriver в переменную среды PATH
-
Выполните перезагрузку системы
💡 Важно! Версия chromedriver
должна соответствовать версии установленного Google Chrome
на вашем ПК
На момент написания инструкции использовалась версия 117.0.5938.92 для ОС Windows x64
Написание первого теста и его локальный запуск
В папке с примерами приведены полные примеры рассматриваемых ниже сценариев, функций, локаторов и настроек.
1. Обозначьте шаги тестового сценария.
Для этого откройте файл test_httpbin.py
и импортируйте в тестовый файл библиотеку allure для сборки отчета, а также укажите название фичи, теста и в тройных кавычках добавьте описание сценария с шагами.
@allure.feature('httpbin-basic-auth')
и @allure.story('Проверка ввода логина и пароля')
— декораторы, с помощью которых сами тесты или тестовые наборы будут структурированы в allure-отчете.
2. Затем нужно определить какие элементы веб-страницы будут задействованы при выполнении сценария и сохранить их локаторы:
2.1 Открыть интересующую страницу в браузере и выбрать элементы, с которыми будет реализовано взаимодействие
Далее нужно определить пути для их поиска на языке XPath.
2.2 Определить XPath заголовка "httpbin.org"
- Кликнуть ПКМ на элементе и в контекстном меню выбрать "Посмотреть код"
- В DevTools браузера на вкладке "Elements" посмотреть, в каком теге html-кода страницы находится заголовок "httpbin.org": тег
h2
, который имеет атрибутclass
со значениемtitle
- Составить путь до элемента на странице, используя полученные данные:
//*[@class='title']
, где//
- для поиска всех элементов на странице, независимо от вложенности (относительный путь)*
- поиск тега с любым названием (вместо конкретного "h2") на случай, если страница изменится и нужный заголовок окажется в другом теге[]
- обозначение предиката, для выборки конкретных узлов по некоторым условиям@class='title'
- условие (поиск элемента, который имеет атрибут "class" со значением "title")
- Проверить, что составленный путь действительно находит только один интересующий нас элемент. Для этого можно выполнить поиск в DevTools браузера на вкладке "Elements", вставив составленный XPath в поле поиска (Ctrl+F)
2.3 Найти XPath для кнопки "Try it out" аналогичным способом
- Найти и изучить элемент в html-коде страницы
- Составить путь до элемента на странице, используя полученные данные:
//button[@class='btn try-out__btn']
, где//
- для поиска всех элементов на странице, независимо от вложенности (относительный путь)button
- название тега, т.к. нас интересует именно кнопка[]
- обозначение предиката, для выборки конкретных узлов по некоторым условиям@class='btn try-out__btn'
- условие (поиск элемента, который имеет атрибут "class" со значением "btn try-out__btn")
- Проверить, что составленный путь действительно находит только один интересующий нас элемент. Здесь мы видим, что необходимо уточнение, т.к. если на нашей странице по каким-то причинам будет раскрыт блок с другим методом аутентификации, то будет отображаться несколько кнопок "Try it out"
Да того, чтобы это исправить, найдем в html-дереве тег, который однозначно идентифицирует блок basic_auth. И такой есть: тег
div
с атрибутомid
, который имеет значениеoperations-Auth-get_basic_auth__user___passwd_
Далее необходимо убедиться, что такой элемент на странице один: - Собрать конструкцию и получить XPath, который ищет блок с Basic Auth, а внутри этого блока ищет кнопку "Try it out".
Получается:
//*[@id='operations-Auth-get_basic_auth__user___passwd_']//button[@class='btn try-out__btn']
2.4 Определить XPath для названий параметров "user" и "passwd"
- Найти элементы в DOM-дереве. В данном случае видно, что это два аналогичных элемента с разным текстом внутри, поэтому можно выполнить поиск тега по названию класса и по вложенному тексту одновременно.
- Составить путь до элемента на странице, используя полученные данные:
//*[@class='parameter__name'][contains(text(),'user')]
, где//
- для поиска всех элементов на странице, независимо от вложенности (относительный путь)*
- поиск любого тега[]
- обозначение предиката для выборки конкретных узлов по некоторым условиям@class='parameter__name'
- первое условие (поиск элемента, который имеет атрибут "class" со значением "parameter__name")contains(text(),'user')
- второе условие (поиск элемента, который содержит в себе текст "user")
- Добавить в начало конструкции поиск нужного нам блока с Basic Auth:
//*[@id='operations-Auth-get_basic_auth__user___passwd_']//*[@class='parameter__name'][contains(text(),'user')]
- Проверить, что составленный путь действительно находит только один интересующий нас элемент.
- Аналогичным образом составить XPath для параметра "passwd":
//*[@id='operations-Auth-get_basic_auth__user___passwd_']//*[@class='parameter__name'][contains(text(),'passwd')]
2.5 Определить пути поиска полей для ввода значений параметров "user" и "passwd"
- Изучить элементы, их атрибуты и расположение.
- Составить путь до каждого элемента на странице, используя полученные данные. Получается:
//*[@id='operations-Auth-get_basic_auth__user___passwd_']//input[@placeholder='user']
и//*[@id='operations-Auth-get_basic_auth__user___passwd_']//input[@placeholder='passwd']
, где//*[@id='operations-Auth-get_basic_auth__user___passwd_']
- поиск блока с Basic Auth//input
- "input" не заменяем на "*" т.к. выполняем поиск именно поля для ввода[@placeholder='user']
или[@placeholder='passwd']
- условие (поиск элемента, который имеет атрибут "placeholder" со значением "user" или "passwd")
- Проверить, что составленный путь действительно находит только один интересующий нас элемент.
2.6 Найти XPath для кнопки "Execute" аналогичным способом
- Изучить элементы, их атрибуты и расположение.
- Составить путь до каждого элемента на странице, используя полученные данные. Получается:
//*[@id='operations-Auth-get_basic_auth__user___passwd_']//button[contains(text(),'Execute')]
, где://*[@id='operations-Auth-get_basic_auth__user___passwd_']
- поиск блока с Basic Auth//button
- название тега, т.к. нас интересует именно кнопка[contains(text(),'Execute']
- условие (поиск элемента, который содержит в себе текст "Execute")
- Проверить, что составленный путь действительно находит только один интересующий нас элемент.
2.7 Открыть файл locators.py
и добавить локаторы
- Выполнить импорт пакета By из библиотеки selenium
- Создать отдельный класс локаторов для удобства их дальнейшего вызова
class LocatorsHttpbin
- Добавить локаторы и оставить комментарии
- Переформатировать файл, чтобы уменьшить длину строки кода
3. В файле settings.py
обозначьте конфигурируемые параметры теста
Для этого потребуется импортировать модуль os, чтобы считывать переменные, а затем – объявить их. В нашем примере в переменные мы вынесем три параметра: локатор ресурса (URL), логин и пароль пользователя.
4. Приступите к написанию самого теста
4.1 Откройте файл page_base.py
и создайте в нём класс BasePage
-
Импортируйте в текущий файл класс
WebDriverWait
и модульexpected_conditions
, а также объявленные вsettings.py
переменные:from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait- В классе BasePage создайте конструктор, который принимает driver — экземпляр webdriver
def __init__(self, driver):
self.driver = driver- Далее создаем метод
find_element
- ищет один элемент и возвращает его:
def find_element(self, locator, time=10):
"""Ищет один элемент и возвращает его, используя явное ожидание"""
return WebDriverWait(self.driver, time).until(EC.presence_of_element_located(locator),
message=f"Can't find element by locator {locator}")Это обертка над WebdriverWait, который отвечает за явные ожидания в Selenium. В функции определяем время, которое по умолчанию равно 10-и секундам. Это время для поиска элемента.
page_base.py
на этом этапе должен выглядеть так:
4.2 Теперь откройте файл page_basic_auth.py
, создайте в нём класс PageHttpbin который наследуется от BasePage:
-
Импортируйте класс BasePage
from page_base import BasePage
-
Создайте класс PageHttpbin с наследованием от BasePage:
class PageHttpbin(BasePage):
-
Добавьте метод
go_to_basic_auth
, который будет использоваться для перехода к выбранному для теста блокуdef go_to_basic_auth(self, base_url):
"""Выполняет переход к методу базовой аутентификации по прямой ссылке и обновление страницы"""
self.driver.get((f"{base_url}/#/Auth/get_basic_auth__user___passwd_"))
return self.driver.refresh()page_basic_auth.py
на этом этапе должен выглядеть так:
4.3 Откройте файл test_httpbin.py
и начните описывать тестовый сценарий:
-
Сначала добавим в файл тестовую функцию test_httpbin с вызовом библиотечной (pytestforge) фикстуры browser в качестве аргумента новой функции. Её необходимо разместить между декораторами allure
@allure.feature
,@allure.story
и описанием сценария в тройных кавычках -
Затем обозначим шаг сценария с помощью контекстного менеджера для формирования allure-отчета с результатами тестирования
with allure.step('Шаг 1. Проверка доступности ресурса'):
Обратите внимание, что название шага должно полностью совпадать с указанным в описании сценария
-
Добавим конструкцию try-except
try:
assert True
allure.attach(browser.get_screenshot_as_png(), name='screenshot', attachment_type=AttachmentType.PNG)
except:
allure.attach(browser.get_screenshot_as_png(), name='error_screen', attachment_type=AttachmentType.PNG)
raiseВ блоке try будут размещены действия и проверка ожидаемого результата по шагу, в случае успешного выполнения будет сделан скриншот экрана. Блок except перехватит исключение(ошибку), есть оно возникнет; также будет сделан скриншот экрана, чтобы прикрепить его к allure-отчету. Аналогичная конструкция будет являться основой для всех последующих шагов
-
В блоке try cоздаём объект страницы
page
. Из этого объекта в дальнейшем будем вызывать методы взаимодействия с элементами страницы, описанные в классеPageHttpbin
.page = PageHttpbin(browser)
-
По задуманному сценарию первое действие, которые выполняется в тесте: переход к httpbin по прямой ссылке, добавим это действие в блок try:
Через фикстуру browser обратимся к методу get и в качестве аргумента передадим переменную BASE_URL
browser.get(BASE_URL)
-
Для проверки ожидаемого результата (далее "ОР") необходимо убедиться, что в элемент страницы, который мы сохранили в качестве локатора TITLE, вложен текст "httpbin.org". Добавим эту проверку:
assert "httpbin.org" in page.find_element(locator=LocatorsHttpbin.TITLE).text
-
Т.к. URL-адрес является переменной BASE_URL, объявленной в другом месте, то необходимо выполнить импорт этого значения в файл с тестом. Аналогично с классами PageHttpbin, LocatorsHttpbin и AttachmentType.
PyCharm подчёркивает ошибки красным цветом и при наведении указателя мыши выдаёт подсказки. В данном случае – предлагает импортировать недостающие пакеты, чем удобно воспользоваться:
test_httpbin.py на этом этапе должен выглядеть так (на скриншоте описание сценария в тройных кавычках свернуто):
4.4 Добавим в файл page_base.py
новые методы, которые будут проверять то, что элемент отображается на странице и кликабельность
def element_is_visible(self, locator, time=20):
"""Проверяет кликабельность элемента и возвращает его, используя явное ожидание"""
return WebDriverWait(self.driver, time).until(EC.visibility_of_element_located(locator),
message=f"Element is not visible {locator}")
def element_is_clickable(self, locator, time=60):
"""Проверяет кликабельность элемента и возвращает его, используя явное ожидание"""
return WebDriverWait(self.driver, time).until(EC.element_to_be_clickable((locator)))
Файл page_base.py на этом этапе должен выглядеть так:
4.5 По аналогии с первым добавим в наш тест второй шаг
С помощью объекта страницы page
вызовем метод go_to_basic_auth
для перехода на нужную страницу и метод element_is_visible
с передачей локатора в качестве аргумента для проверки отображения элементов:
with allure.step('Шаг 2. Проверка доступности перехода к методу "basic_auth" по прямой ссылке.'):
try:
page.go_to_basic_auth(BASE_URL)
assert page.element_is_visible(LocatorsHttpbin.PARAMETER_NAME_USER)
assert page.element_is_visible(LocatorsHttpbin.PARAMETER_NAME_PASSWD)
allure.attach(browser.get_screenshot_as_png(), name='screenshot', attachment_type=AttachmentType.PNG)
except:
allure.attach(browser.get_screenshot_as_png(), name='error_screen', attachment_type=AttachmentType.PNG)
raise
4.6 Для выполнения третьего шага требуется заполнить поля значений для "user" и "passwd", а затем проверить, что поля успешно заполнены. Реализуем в файле page_basic_auth.py
соответствующие методы
def fill_fields_user_passwd(self, login, password):
"""Заполняет поля user и passwd значениями, переданными в качестве аргументов"""
try:
self.find_element(LocatorsHttpbin.INPUT_PARAMETER_USER).send_keys(login)
self.find_element(LocatorsHttpbin.INPUT_PARAMETER_PASSWD).send_keys(password)
except Exception as err:
pytest.fail("Не удалось заполнить поля user и passwd:" + str(err))
def check_field_values_user_passwd(self, login, password):
"""Сравнивает значения в полях user и passwd с переданными в качестве аргументов"""
try:
failures = []
user_value = self.find_element(LocatorsHttpbin.INPUT_PARAMETER_USER).get_attribute("value")
passwd_value = self.find_element(LocatorsHttpbin.INPUT_PARAMETER_PASSWD).get_attribute("value")
if not user_value == login:
failures.append(f'Неверное значение в поле "user": {user_value} != {login}')
if not passwd_value == password:
failures.append(f'Неверное значение в поле "passwd": {passwd_value} != {password}')
if not failures:
return True
else:
pytest.fail(f"{failures}")
except Exception as err:
pytest.fail("Не удалось выполнить проверку значений:" + str(err))
При необходимости выполните в файл импорт pytest
.
page_basic_auth.py
на этом этапе должен выглядеть так:
4.7 Добавьте в файл с тестом test_httpbin.py
третий шаг
-
Выполните импорт оставшихся переменных окружения в файл:
from settings import *
-
С помощью метода
click
вызовите срабатывание события клика ЛКМ по кнопке "Try it out", а затем используйте новые методыfill_fields_user_passwd
иcheck_field_values_user_passwd
с передачей USER_LOGIN и USER_PASSWORD:with allure.step('Шаг 3. Проверка возможности указания значений для "user" и "passwd"'):
try:
page.element_is_clickable(LocatorsHttpbin.BUTTON_TRY_IT_OUT).click()
page.fill_fields_user_passwd(login=USER_LOGIN, password=USER_PASSWORD)
assert page.check_field_values_user_passwd(login=USER_LOGIN, password=USER_PASSWORD)
allure.attach(browser.get_screenshot_as_png(), name='screenshot', attachment_type=AttachmentType.PNG)
except:
allure.attach(browser.get_screenshot_as_png(), name='error_screen', attachment_type=AttachmentType.PNG)
raise
4.8 Аналогично предыдущим допишите четвертый шаг тестового сценария
with allure.step('Шаг 4. Проверка кликабельности кнопки Execute.'):
try:
page.element_is_clickable(LocatorsHttpbin.BUTTON_EXECUTE).click()
allure.attach(browser.get_screenshot_as_png(), name='screenshot', attachment_type=AttachmentType.PNG)
except:
allure.attach(browser.get_screenshot_as_png(), name='error_screen', attachment_type=AttachmentType.PNG)
pytest.fail("Не удалось нажать на кнопку 'Execute'")
raise
5. Выполните локальный запуск теста, чтобы убедиться, что он работает корректно
Для локального запуска теста в Google Chrome необходим ChromeDriver. Если он у вас еще не установлен, то обратитесь к разделу Установка ChromeDriver.
5.1 Создайте новую конфигурацию запуска
-
Через главное меню откройте Run - Edit Configurations
-
Нажмите Add new для добавления новой конфигурации, выберите из списка Python tests - pytest
5.2 Настройте конфигурацию запуска:
-
Name - произвольное название конфигурации
-
Target - Script path - путь к Python-скрипту (тестовому файлу)
-
Additional Arguments - аргументы запуска =
--alluredir ./allure-results --clean-alluredir
, где--alluredir ./allure-results
- директория для сохранения allure-отчета: в корневой папке проекта создать папку "allure-results"--clean-alluredir
- очистить директорию для allure-отчета перед новым запуском теста -
Environment variables - переменные окружения для запуска
Переменные, используемые в тесте:
- BASE_URL - адрес запущенного экземпляра Httpbin, полученный в разделе Запуск HTTPbin, например
http://172.11.222.333:8888
- USER_LOGIN - логин пользователя
- USER_PASSWORD - пароль пользователя
Переменные, используемые плагином pytestforge:
- SEND_REPORT - Флаг отправки allure отчета в Monq = False
- LOCAL_DRIVER - Флаг использования локального chromedriver = True
- HUB_ENABLE_VNC - Флаг включения VNC в selenoid/moon = True
- 💡Информация обо всех переменных окружения доступна в описании плагина pytestforge
- BASE_URL - адрес запущенного экземпляра Httpbin, полученный в разделе Запуск HTTPbin, например
-
Working directory - путь к корневой папке проекта
-
Сохраните изменения
5.3 Выполните локальный запуск теста
- Через главное меню откройте Run - Run и выберите конфигурацию запуска
- Проверьте результат:
- Запуск успешно сконфигурирован и выполнен
- Статус теста по завершению = passed
- В указанную в настройках директорию сохранен allure-отчет
- В отчете присутствуют скриншоты
6. Перенесите готовый тест на виртуальную машину для выполнения дальнейших инструкций
В примерах будет рассматриваться такое размещение теста: /opt/tests/httpbinTest/test_httpbin.py
Настройка среды для выполнения тестов с помощью Docker и Selenoid и запуск разработанного теста на удаленном браузере
Теперь, когда мы можем писать собственные тесты и запускать их локально, настроим их запуск на удаленной машине, которая будет служить средой их исполнения. Предполагается, что перед выполнением дальнейших шагов у вас уже есть:
- Виртуальная машина с ОС Debian 10/11 с установленными:
- python3 (версия 3.9)
- pip
Рассмотрим пошаговый процесс подготовки стенда функционального тестирования для исполнения функциональных тестов и отправки результатов в Monq.
Установка плагина pytestforge
Установите плагин pytestforge для pytest и все его зависимости:
pip install pytestforge==1.2.0
Информация об успешной установке будет выглядеть следующим образом:
Successfully installed allure-pytest-2.12.0 allure-python-commons-2.12.0 attrs-23.1.0 iniconfig-2.0.0 packaging-23.1 pluggy-0.13.1 py-1.11.0 pytest-6.1.0 pytestforge-1.2.0 selenium-3.141.0 seleniumwrapper-0.5.4 toml-0.10.2 urllib3-1.26.12
Установка Docker
Docker понадобится для запуска Selenoid, а также сборки контейнера со всем набором ПО для запуска тестов.
apt update && apt install -y ca-certificates gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt update
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
systemctl enable docker --now
Установка и запуск Selenoid
Установку Selenoid вы можете произвести при помощи Configuration Manager от Aerokube (https://github.com/aerokube/cm/releases/latest).
Установка коммерческой версии Moon в данном документе не рассматривается, вы можете изучить ее из официальных источников - https://aerokube.com/moon/latest/
Скачайте последнюю версию Configuration Manager:
curl -Lso /usr/bin/cm https://github.com/aerokube/cm/releases/download/1.8.5/cm_linux_amd64 && chmod +x /usr/bin/cm
Произведите запуск Selenoid
cm selenoid start --vnc --browsers 'chrome' --last-versions 2
После запуска Selenoid будет доступен по следующему адресу:
http://<virtual-machine-ip>:4444/wd/hub
Настройка автономного проекта автотестирования в Monq
После того, как мы научились локально запускать автотест и формировать отчет, нам необходимо настроить проект в Monq для приема результирующих артефактов сборок тестов.
Перейдите в Monq и в разделе Автотесты создайте проект с типом “Автономный”:
Активируйте проект. Далее перейдите на вкладку “Общая информация” и скопируйте API ключ проекта.
В разделе Автоматизация импортируйте, скомпилируйте и запустите сценарий автоматизации для последующего парсинга отчетов тестирования:
Скачать сценарий можно по ссылке из нашего репозитория в Github.
Отправка Allure-отчета в Monq
Отправим результирующий артефакт теста в настроенный на предыдущем шаге проект. Для этого нам нужно запустить наш тест.
Задайте переменные окружения для запуска теста при помощи плагина pytestforge:
export X_FMONQ_PROJECT_KEY="<API-ключ>" \
export HUB_URL="<Адрес Selenoid>" \
export AGGREGATOR_URL="<FQDN-имя Monq>" \
export SEND_VERIFY_SSL=False \
export BASE_URL="<Адрес HTTPBin>" \
export USER_LOGIN="<Тестовый логин>" \
export USER_PASSWORD:="<Тестовый пароль>"
Например, так:
export X_FMONQ_PROJECT_KEY="a316b45c-58b1-4ff0-a62b-f24a783fc67c" \
export HUB_URL="http://localhost:4444/wd/hub" \
export AGGREGATOR_URL="demo.monq.ru" \
export SEND_VERIFY_SSL=False \
export BASE_URL="http://localhost:8888/"
export USER_LOGIN="testUser" \
export USER_PASSWORD:="testPassword"
Запустите тест через pytest:
pytest /opt/tests/httpbinTest/test_httpbin.py --alluredir ./allure-results --clean-alluredir
Перейдите на вкладку сборки и убедитесь, что сборка появилась в ранее созданном проекте:
Сборка и запуск Docker контейнера
Для того, чтобы управлять расписанием запуска тестов или запускать тест со своими параметрами из Monq, необходимо выполнить следующее:
- Создать на стороне Monq координатор агентов.
- Подготовить контейнер с monq-агентом - именно monq-агент будет получать команду от Monq на запуск теста.
- Подготовить тестовый сценарий.
- Настроить на стороне Monq управляемый проект автотестирования.
1. Создайте в Monq координатор агентов
Справка по работе с координаторами в документации.
2. Подготовьте Docker-контейнер
Создайте каталог и поместите в него 3 файла:
Dockerfile
- для сборки контейнераagent.conf.j2
- шаблон конфигурационного файла агентаentrypoint.sh
- точка входа, выполняющая скачивание "Monq Agent", его настройку и запуск
Пример Dockerfile
:
FROM python:3.9-slim-bullseye
ENV MONQ_AGENT_TIMEOUT="3600"
ENV AGENT_SLOTS=2
ENV AGENT_VERSION="latest"
ENV AGENT_INSECURE="true"
ENV PYTESTFORGE_VERSION="1.2.0"
ENV PIP_ROOT_USER_ACTION=ignore
RUN apt-get update && apt-get -y install \
zip \
wget \
libgssapi-krb5-2 \
curl \
libssl-dev \
libicu67 \
ca-certificates \
gettext-base \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
mkdir -p /opt/monq-agent
RUN pip install --upgrade pip
RUN pip install pytestforge==${PYTESTFORGE_VERSION}
WORKDIR /opt/monq-agent
COPY entrypoint.sh /
COPY agent.conf.j2 /tmp/
ENTRYPOINT ["bash", "/entrypoint.sh"]
Файл agent.conf.j2
:
BaseUri="${AGENT_BASEURI}"
ApiKey="${AGENT_APIKEY}"
FileStorage=""
Timeout=${MONQ_AGENT_TIMEOUT}
[Plugins]
CSharpPath="/opt/monq-agent/plugins"
[Connection]
Timeout=${MONQ_AGENT_TIMEOUT}
RetryCount=10
[Agent]
Name="${AGENT_NAME}"
SlotsCount=${AGENT_SLOTS}
Файл entrypoint.sh
:
#!/bin/bash
echo "- Start configuration"
if [ -z ${AGENT_BASEURI+x} ]; then echo "ERROR: Var unset AGENT_BASEURI";exit 1;fi
if [ -z ${AGENT_APIKEY+x} ]; then echo "ERROR: Var unset AGENT_APIKEY";exit 1;fi
echo "-- Installing monq_agent ${AGENT_VERSION}"
if [ -f /opt/monq-agent/monq-agent ]; then
echo "--- monq-agent already installed"
else
wget -q -O /tmp/monq-agent.zip https://downloads.monq.ru/tools/monq-agent/${AGENT_VERSION}/linux-x64/monq-agent.zip
unzip -qq /tmp/monq-agent.zip -d /opt/monq-agent
rm -f /tmp/monq-agent.zip
echo "--- monq-agent successfully installed"
fi
echo "-- Configuring monq-agent"
cat /tmp/agent.conf.j2 | envsubst > /opt/monq-agent/monitoring-agent.conf
echo "-- Start monq-agent"
if [[ $AGENT_INSECURE == "true" ]]; then
AGENT_ARGS="--insecure"
else
AGENT_ARGS=""
fi
/opt/monq-agent/monq-agent start --config /opt/monq-agent/monitoring-agent.conf ${AGENT_ARGS}
3. Соберите контейнер
Когда все файлы сохранены в отдельной директории, при помощи команды docker build
нужно собрать образ контейнера для дальнейшего переиспользования:
Перейдите в директорию с файлами и выполните команду:
docker build -t monq-agent-docker:1.0 .
4. Запустите контейнер
После успешной сборки запустить собранный образ можно следующей командой:
docker run --name monq-agent \
--restart=always \
-e AGENT_BASEURI="https://demo.monq.ru" \
-e AGENT_APIKEY="123456" \
-v /opt/tests:/opt/tests \
--rm \
monq-agent-docker:1.0
При запуске контейнера необходимо задать обязательные параметры:
AGENT_BASEURI
- адрес MonqAGENT_APIKEY
- API ключ координатора "Monq Agent", который будет использоваться при запуске проекта автотеста.
Если все сделано правильно, агент подключится к координатору и будет ожидать распределения заданий на запуск тестов от Monq.
Конфигурация управляемого проекта автотестирования
К этому моменту у вас уже должен быть:
- запущен Httpbin
- готов автотест
- запущен отдельно selenoid или moon
- запущен Docker контейнер с "Monq Agent" и подключен к координатору
- запущен сценарий обработки Allure-отчетов в Monq
Перейдите в Monq и в разделе Автотесты создайте проект с типом “Управляемый”:
-
Перейдите на вкладку Конфигурация проекта и составьте задание, запускающее сборку проекта, с указанием значений переменных и пути к файлам теста:
name: HttpBin Test
env:
BUILD_NUMBER: $.vars.params.buildId
PROJECT: $.vars.params.projectId
X_FMONQ_PROJECT_KEY: $.vars.params.projectKey
AGGREGATOR_URL: $.vars.params.testforgeUri
HUB_URL: $.vars.params.hubUrl
BASE_URL: $.vars.params.baseUrl
USER_LOGIN: $.vars.params.userLogin
USER_PASSWORD: $.vars.params.userPass
jobs:
- steps:
- name: Run test
run: python -m pytest /opt/tests/httpbinTest/test_httpbin.py --alluredir /tmp/${PROJECT} --clean-alluredirПредполагается, что контейнер запущен с верно примонтированным
Volume
и путь к файлу теста корректный -
Добавьте переменные окружения и их значения в проект
-
Задайте расписание запуска и укажите метку координатора, на котором запущен агент
-
Сохраните изменения и запустите проект
-
Дождитесь выполнения запуска по расписанию
-
Проверьте результат: перейдите на вкладку "Сборки" созданного проекта и убедитесь, что новая сборка появилась
Предполагается, что контейнер запущен с верно примонтированным
Volume
и путь к файлу теста корректный.
Теперь вы можете управлять расписанием запусков теста из Monq и даже выполнять их внеочередно через кнопку "Выполнить сборку".
Расчет мощностей для развертывания среды исполнения тестов
Теперь перед нами может встать вопрос: "Сколько ресурсов мне нужно заложить на сервер выполнения тестов, чтобы они выполнялись с желаемым расписанием и не конфликтовали друг с другом?".
Расчет мощностей для среды исполнения тестов зависит от планируемых к запуску тестов:
- Какие сайты и приложения будут тестироваться? На сайтах может быть различное количество скриптов, изображений, интерактивных элементов, влияющих на потребление оперативной памяти.
- Количество шагов в сценарии проверки, длительность шагов, частота запуска тестов.
- В каких браузерах выполняются тесты: различные браузеры могут выдвигать различные требования к ресурсам для рендеринга страниц.
Для запуска одного экземпляра теста в Selenoid разработчик рекомендует начинать с выделения 1 CPU и 1 RAM на каждый контейнер (и инкрементально увеличивать лимиты до стабилизации выполнения теста).
Можно воспользоваться следующей методикой расчета необходимых вычислительных мощностей:
CPU = CPUavg_consumption_pertest * TestCount * Utilization
RAM = RAMavg_consumption_pertest * TestCount * Utilization
где:
- CPUavg_consumption - cреднее использование CPU для одного теста
- RAMavg_consumption - cреднее использование RAM для одного теста
- TestCount - общее количество тестов
- Utilization - % использования вычислительных ресурсов за час
Utilization = (Продолжительность теста в минутах * Сколько раз будет выполнено за час) / 60
Например, мы хотим рассчитать емкость среды для запуска тестов со следующими параметрами:
- Количество тестов - 60 тестов
- Частота запуска теста - раз в 5 минут
- Среднее количество шагов в тестах - 7 шагов
- Среднее время выполнения каждого шага - 30 секунд
- Среднее потребление CPU и RAM - по "1" соотвественно, т.к. в нашем примере предполагаем тестировать "легковесные" веб-приложения.
Для запуска тестов с такими параметрами потребуется машина с мощностями: CPU = 1 * 60 * 0,7 = 42 ядра RAM = 1 * 60 * 0,7 = 42 гигабайта памяти
Т.к.:
- продолжительность теста в минутах в среднем : 7 шагов по 30 сек = 210 сек = 3,5 мин
- будет выполнено за час каждого теста в среднем: 60 / 5 = 12 раз
- таким образом, время использования стенда ФТ одним тестом за один час будет 42 минуты (3,5 * 12 = 42), т.е. стенд будет утилизирован на 70% одним тестом
Расчет емкости хранения среды тестирования выполняется аналогичным образом и зависит от:
- размера архива содержащего данные о результате теста (зависит от количества картинок, их качества)
- частоты запуска тестов
- глубины хранения
Хранение тестов и их сборка
Также, если на момент организации среды для выполнения синтетического тестирования не развернуто какого-либо репозитория для версионирования кода тестов, то необходимо предусмотреть мощности для развертывания и этого ПО.
Изучите требования к ресурсам в документации соответствующего производителя, например: