Автотесты
Введение
💡 В статье отражены возможные подходы как к написанию тестов, так и настройке среды исполнения тестов - рассмотренные варианты не являются единственно верными и отражают только наш опыт.
В данной статье будут показаны этапы, предваряющие прием и обработку отчетов о выполнении синтетических тестов на платформе 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 -d 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 подчёркивает ошибки красным цветом и при наведении указателя мыши выдаёт подсказки. В данном случае – предлагает импортировать недостающие пакеты, чем удобно воспользоваться:
![image](images/image36.png)
**test_httpbin.py** на этом этапе должен выглядеть так (на скриншоте описание сценария в тройных кавычках свернуто):
![image](images/image37.png)
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
- python3 (версия 3.9)
Рассмотрим пошаговый процесс подготовки стенда функционального тестирования для исполнения функциональных тестов и отправки результатов в 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 \
-e AGENT_BASEURI="https://demo.monq.ru" \
-e AGENT_APIKEY="123456" \
-v /opt/tests:/opt/tests \
-d --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% одним тестом
Расчет емкости хранения среды тестирования выполняется аналогичным образом и зависит от:
- размера архива содержащего данные о результате теста (зависит от количества картинок, их качества)
- частоты запуска тестов
- глубины хранения
Хранение тестов и их сборка
Также, если на момент организации среды для выполнения синтетического тестирования не развернуто какого-либо репозитория для версионирования кода тестов, то необходимо предусмотреть мощности для развертывания и этого ПО.
Изучите требования к ресурсам в документации соответствующего производителя, например: