Перейти к основному содержимому
Версия: 8.5

Автотесты

Введение

💡 В статье отражены возможные подходы как к написанию тестов, так и настройке среды исполнения тестов - рассмотренные варианты не являются единственно верными и отражают только наш опыт.

В данной статье будут показаны этапы, предваряющие прием и обработку отчетов о выполнении синтетических тестов на платформе 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Расчет мощностей для развертывания среды тестированияРассмотрим методику расчета ресурсов для среды исполнения тестов.Расчет мощностей для развертывания среды тестирования

Предполагается, что пользователь пройдет следующий путь:

  1. Научится разрабатывать базовые тесты и запускать их локально на своей машине.
  2. Далее научится запускать разработанные тесты на удаленном сервере и направлять их результаты в Monq.
  3. Освоит конфигурирование "Управляемых проектов" и подготовку среды исполнения тестов для управления тестами напрямую из Monq.

💡 Предполагается, что читатель этого материала знаком с основами Linux, Docker и Python.

Прежде, чем мы перейдем к деталям разработки и отладки тестов на вашей локальной машине, давайте убедимся, что у вас имеется всё необходимое:

  • Docker
  • Python - в данной инструкции мы будем рассматривать работу с Python версии 3.9, т.к. будем использовать зависимую библиотеку pytestforge
  • pip (Python Package Installer) - обычно устанавливается вместе с Python по умолчанию, но, если у вас старая версия, то, возможно, потребуется поставить дополнительно
  • IDE Pycharm

Определение объекта и тактики его тестирования

Перед тем, как приступить к написанию кода тестов, необходимо выполнить следующие шаги тест-дизайна:

  1. Определение цели тестирования: Четко сформулируйте, что вы хотите проверить с помощью автотестов. Это может быть функциональность, интерфейс, производительность или другие аспекты работы приложения.
  2. Идентификация объекта тестирования: Определите, какая часть приложения будет подвергнута тестированию. Это может быть конкретная страница веб-сайта, модуль программы или API.
  3. Создание тестовых сценариев: Разработайте тестовые сценарии, которые описывают последовательность действий пользователя. Эти сценарии должны включать в себя клики, ввод данных, навигацию и другие действия.
  4. Определение шагов и ожидаемых результатов: Для каждого тестового сценария определите конкретные шаги, которые должны быть выполнены, и ожидаемые результаты для каждого шага. Это позволит более точно проверять функциональность.
  5. Настройка окружения и данных: Подготовьте окружение для выполнения тестов, включая установку необходимых зависимостей и настройку данных, если тесты требуют ввода или загрузки определенных данных.

В примере, выбранном для данной статьи, целью тестирования является проверка работоспособности одного из методов аутентификации в приложении HTTPbin, а именно объектом избран Basic Auth.

Мы рассмотрим один сценарий:

  1. Открытие страницы сайта -> Страница открыта, на ней отображено и найдена контрольная фраза для проверки.
  2. Переход к методу Basic Auth -> Блок и его ключевые элементы доступны.
  3. Клик в кнопку "Try it out" и указание логина и пароля -> Поля успешно заполнены значениями.
  4. Клик "Execute" -> Кнопка кликабельна.

Запуск Httpbin

Как мы и определились на предыдущем этапе, наш тест будет проверять корректность работы функционала авторизации в приложении httpbin. Запустим HTTPbin локально в docker - на нем мы сможем локально отлаживать свои тесты:

Запустите httpbin:

docker run -p 8888:80 --rm --name httpbin kennethreitz/httpbin

После запуска httpbin будет доступен по адресу

http://<virtual-machine-ip>:8888/

Настройка PyCharm

1. Создайте новый проект и виртуальное окружение

image image

2. После создания проекта откройте терминал и установите в виртуальное окружение библиотеку pytestforge. Требуемые пакеты установятся автоматически

Для этого откройте терминал выполните команду:

pip install pytestforge==1.2.0

image

После успешной установки необходимых пакетов окружение готово.

3. Теперь необходимо обозначить структуру проекта для удобства дальнейшей работы с ним

Для этого в корневой папке проекта создайте файлы:

image

  • test_httpbin.py - здесь будет размещен тестовый сценарий
  • locators.py - в этом файле будут храниться локаторы для поиска элементов на странице
  • page_base.py - общие функции и методы для работы со страницами
  • page_basic_auth.py - функции и методы для работы с конкретной страницей
  • settings.py - файл с настройками

image

Если вы планируете создать большой проект, то рекомендуем сразу создавать отдельные каталоги для хранения файлов:

  • с локаторами для каждой из страниц - locators
  • с файлами, которые содержат методы взаимодействий с каждой страницей, - pages
  • с тестами - tests
  • прочие, в зависимости от конкретного проекта

Для локальной отладки тестов в PyCharm будет полезен ChromeDriver для запуска и прогона тестов в Google Chrome. Если у вас он еще не установлен, то обратитесь к разделу Установка ChromeDriver.

4. Установка chromedriver

  1. Скачайте chromedriver соответствующий версии установленного браузера Google Chrome и вашей ОС

    Доступные версии chromedriver можно найти по ссылкам:

  2. Распакуйте драйвер в папку на диске, например C:\chromedriver

  3. Добавьте папку с chromedriver в переменную среды PATH image

  4. Выполните перезагрузку системы

💡 Важно! Версия chromedriver должна соответствовать версии установленного Google Chrome на вашем ПК

На момент написания инструкции использовалась версия 117.0.5938.92 для ОС Windows x64

Написание первого теста и его локальный запуск

В папке с примерами приведены полные примеры рассматриваемых ниже сценариев, функций, локаторов и настроек.

1. Обозначьте шаги тестового сценария.

Для этого откройте файл test_httpbin.py и импортируйте в тестовый файл библиотеку allure для сборки отчета, а также укажите название фичи, теста и в тройных кавычках добавьте описание сценария с шагами.

@allure.feature('httpbin-basic-auth') и @allure.story('Проверка ввода логина и пароля') — декораторы, с помощью которых сами тесты или тестовые наборы будут структурированы в allure-отчете.

image

2. Затем нужно определить какие элементы веб-страницы будут задействованы при выполнении сценария и сохранить их локаторы:

2.1 Открыть интересующую страницу в браузере и выбрать элементы, с которыми будет реализовано взаимодействие

image

Далее нужно определить пути для их поиска на языке XPath.

2.2 Определить XPath заголовка "httpbin.org"

  • Кликнуть ПКМ на элементе и в контекстном меню выбрать "Посмотреть код"
  • В DevTools браузера на вкладке "Elements" посмотреть, в каком теге html-кода страницы находится заголовок "httpbin.org": тег h2, который имеет атрибут class со значением title image
  • Составить путь до элемента на странице, используя полученные данные: //*[@class='title'], где
    • // - для поиска всех элементов на странице, независимо от вложенности (относительный путь)
    • * - поиск тега с любым названием (вместо конкретного "h2") на случай, если страница изменится и нужный заголовок окажется в другом теге
    • [] - обозначение предиката, для выборки конкретных узлов по некоторым условиям
    • @class='title' - условие (поиск элемента, который имеет атрибут "class" со значением "title")
  • Проверить, что составленный путь действительно находит только один интересующий нас элемент. Для этого можно выполнить поиск в DevTools браузера на вкладке "Elements", вставив составленный XPath в поле поиска (Ctrl+F)

image

2.3 Найти XPath для кнопки "Try it out" аналогичным способом

  • Найти и изучить элемент в html-коде страницы image
  • Составить путь до элемента на странице, используя полученные данные: //button[@class='btn try-out__btn'], где
    • // - для поиска всех элементов на странице, независимо от вложенности (относительный путь)
    • button - название тега, т.к. нас интересует именно кнопка
    • [] - обозначение предиката, для выборки конкретных узлов по некоторым условиям
    • @class='btn try-out__btn' - условие (поиск элемента, который имеет атрибут "class" со значением "btn try-out__btn")
  • Проверить, что составленный путь действительно находит только один интересующий нас элемент. Здесь мы видим, что необходимо уточнение, т.к. если на нашей странице по каким-то причинам будет раскрыт блок с другим методом аутентификации, то будет отображаться несколько кнопок "Try it out" image Да того, чтобы это исправить, найдем в html-дереве тег, который однозначно идентифицирует блок basic_auth. И такой есть: тег div с атрибутом id, который имеет значение operations-Auth-get_basic_auth__user___passwd_ image Далее необходимо убедиться, что такой элемент на странице один: image
  • Собрать конструкцию и получить 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-дереве. image В данном случае видно, что это два аналогичных элемента с разным текстом внутри, поэтому можно выполнить поиск тега по названию класса и по вложенному тексту одновременно.
  • Составить путь до элемента на странице, используя полученные данные: //*[@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"

  • Изучить элементы, их атрибуты и расположение. image
  • Составить путь до каждого элемента на странице, используя полученные данные. Получается: //*[@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" аналогичным способом

  • Изучить элементы, их атрибуты и расположение.

image

  • Составить путь до каждого элемента на странице, используя полученные данные. Получается: //*[@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
  • Добавить локаторы и оставить комментарии image
  • Переформатировать файл, чтобы уменьшить длину строки кода image

3. В файле settings.py обозначьте конфигурируемые параметры теста

Для этого потребуется импортировать модуль os, чтобы считывать переменные, а затем – объявить их. В нашем примере в переменные мы вынесем три параметра: локатор ресурса (URL), логин и пароль пользователя. image

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 на этом этапе должен выглядеть так:

    image

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 на этом этапе должен выглядеть так: image

4.3 Откройте файл test_httpbin.py и начните описывать тестовый сценарий:

  • Сначала добавим в файл тестовую функцию test_httpbin с вызовом библиотечной (pytestforge) фикстуры browser в качестве аргумента новой функции. Её необходимо разместить между декораторами allure @allure.feature, @allure.story и описанием сценария в тройных кавычках

    image

  • Затем обозначим шаг сценария с помощью контекстного менеджера для формирования allure-отчета с результатами тестирования

        with allure.step('Шаг 1. Проверка доступности ресурса'):

    Обратите внимание, что название шага должно полностью совпадать с указанным в описании сценария image

  • Добавим конструкцию 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

    test_httpbin.py на этом этапе должен выглядеть так (на скриншоте описание сценария в тройных кавычках свернуто):

    image

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 на этом этапе должен выглядеть так: image

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 на этом этапе должен выглядеть так:

image

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

    image

  • Нажмите Add new для добавления новой конфигурации, выберите из списка Python tests - pytest image

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 - переменные окружения для запуска

    image Переменные, используемые в тесте:

    • 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 image
  • Working directory - путь к корневой папке проекта

  • Сохраните изменения

5.3 Выполните локальный запуск теста

  • Через главное меню откройте Run - Run и выберите конфигурацию запуска image
  • Проверьте результат:
    • Запуск успешно сконфигурирован и выполнен
    • Статус теста по завершению = passed
    • В указанную в настройках директорию сохранен allure-отчет
    • В отчете присутствуют скриншоты image

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 и в разделе Автотесты создайте проект с типом “Автономный”:

image

Активируйте проект. Далее перейдите на вкладку “Общая информация” и скопируйте API ключ проекта.

image

В разделе Автоматизация импортируйте, скомпилируйте и запустите сценарий автоматизации для последующего парсинга отчетов тестирования:

image

Скачать сценарий можно по ссылке из нашего репозитория в 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

Перейдите на вкладку сборки и убедитесь, что сборка появилась в ранее созданном проекте: image

Сборка и запуск 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- адрес Monq
  • AGENT_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 и путь к файлу теста корректный

  • Добавьте переменные окружения и их значения в проект image

  • Задайте расписание запуска и укажите метку координатора, на котором запущен агент

  • Сохраните изменения и запустите проект

  • Дождитесь выполнения запуска по расписанию

  • Проверьте результат: перейдите на вкладку "Сборки" созданного проекта и убедитесь, что новая сборка появилась image

Предполагается, что контейнер запущен с верно примонтированным 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% одним тестом

Расчет емкости хранения среды тестирования выполняется аналогичным образом и зависит от:

  • размера архива содержащего данные о результате теста (зависит от количества картинок, их качества)
  • частоты запуска тестов
  • глубины хранения

Хранение тестов и их сборка

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

Изучите требования к ресурсам в документации соответствующего производителя, например:

  1. Gitlab
  2. Github
  3. Bitbucket