- Описание
- Как работает
- Настройка окружения
- Связка с Selenium
- Где применяется
- Лучшие практики
- Известные проблемы
- ЧаВо
Что такое tox
Инструмент командной строки для управления виртуальными окружениями и автоматизации тестирования на Python.
Позволяет тестировать код в нескольких окружениях, обеспечивая его работоспособность и надежность независимо от версий и конфигураций Python.
С открытым исходным кодом, активно обновляемый на GitHub. Есть функции изоляции окружения, которая позволяет тестам выполняться независимо друг от друга.
tox обладает многочисленными преимуществами:
- Обеспечивает надежное тестирование в опенсорсных проектах, предотвращая проблемы после добавления нового кода.
- Создает изолированные окружения, устраняя несоответствия между системами.
- Автоматизирует тестирование для нескольких версий Python, ОС, и зависимостей.
- Интегрируется с инструментами CI, например Jenkins и GitHub Actions.
- Позволяет настраивать систему плагинов для проекта.
Как работает
Tox помогает автоматизировать и стандартизировать рабочие процессы тестирования, управляя виртуальными окружениями, зависимостями и командами.
Как работает tox:
- Конфигурация: tox считывает файл
tox.ini
, в котором указаны окружения, зависимости и команды, необходимые для тестирования. Эта конфигурация служит основой для всего процесса. - Создание окружения: Для каждого окружения, указанного в конфигурации, tox создает изолированные виртуальные окружения. Это гарантирует, что зависимости и инструменты одного окружения не будут мешать другим, поддерживая согласованность и воспроизводимость.
- Установка зависимостей: После создания виртуальных окружений tox устанавливает указанные зависимости (например, pytest, Selenium или другие необходимые библиотеки) для каждого окружения.
- Выполнение команд: После настройки окружения и зависимостей tox запускает команды, то есть тестовые скрипты, линтеры или процессы сборки, в каждом окружении.
- Отчет о результатах: tox собирает результаты из всех окружений и предоставляет пользователю сводный отчет, позволяющий выявить проблемы или несоответствия.
Все операции в tox хранятся в каталоге .tox
, что упрощает управление и отладку.
Настройка окружения Python
Мы будем работать со связкой Python + Selenium, а также плагином pytest, на платформе LambdaTest.
- Скачайте и установите Python. Обязательно выберите опцию «Добавить Python в PATH», чтобы получить к нему доступ из командной строки.
- Выполните команду установки библиотек Selenium, pytest и tox:
pip install -r requirements.txt
Файл requirements.txt
содержит необходимые зависимости.
- Нужен IDE, например VS Code или PyCharm. Мы будем использовать VS Code.
- Чтобы запустить Selenium-тесты на LambdaTest, настройте их с помощью Automation Capabilities Generator.
После этого введите свои учетные данные в качестве переменных окружения:
export LT_USERNAME=your-lambdatest-username export LT_ACCESS_KEY=your-lambdatest-access-key
Теперь мы готовы приступать.
tox + Selenium
Наш тестовый сценарий:
- Открыть форму регистрации аккаунта в LambdaTest eCommerce Playground.
- Заполнить данные.
- Подписаться на новостную рассылку.
- Принять условия.
- Нажать кнопку «Продолжить».
- Проверить, что пользователю показано сообщение об успешной регистрации.
Реализация (tox.ini):
[tox] envlist = py{39,311}-chrome, py{39,311}-firefox [testenv] deps = pytest selenium passenv = LT_USERNAME LT_ACCESS_KEY setenv = PLATFORM_NAME = Windows 11 SELENIUM_VERSION = 4.0 commands = pytest -s [testenv:py39-chrome] setenv = BROWSER_NAME = Chrome BROWSER_VERSION = latest BUILD_NAME = Tox Chrome Python 3.9 Tests TEST_NAME = Chrome Test Python 3.9 [testenv:py39-firefox] setenv = BROWSER_NAME = Firefox BROWSER_VERSION = latest BUILD_NAME = Tox Firefox Python 3.9 Tests TEST_NAME = Firefox Test Python 3.9 [testenv:py311-chrome] setenv = BROWSER_NAME = Chrome BROWSER_VERSION = latest BUILD_NAME = Tox Chrome Python 3.11 Tests TEST_NAME = Chrome Test Python 3.11 [testenv:py311-firefox] setenv = BROWSER_NAME = Firefox BROWSER_VERSION = latest BUILD_NAME = Tox Firefox Python 3.11 Tests TEST_NAME = Firefox Test Python 3.11
Объяснение кода:
Список envlist
задает матрицу окружений для запуска тестов в Tox. Это гарантирует, что тесты будут выполняться на нескольких версиях Python и комбинациях браузеров, что улучшает покрытие.
В секции [testenv
] находится раздел deps
, в котором прописаны pytest и selenium, что позволяет выполнять тесты с помощью pytest и автоматизировать браузеры с помощью Selenium.
passenv
позволяет обращаться к переменным окружения (LT_USERNAME
и LT_ACCESS_KEY
) с помощью tox. Эти переменные необходимы для аутентификации на LambdaTest.
setenv
задает значения по умолчанию для PLATFORM_NAME
(операционная система) и SELENIUM_VERSION
, которые необходимы для настройки LambdaTest.
Флаг pytest -s
запускает тесты, при этом флаг -s
используется для отключения вывода (для улучшения читаемости логов). В окружении py39-chrome
BROWSER_NAME
и BROWSER_VERSION
устанавливаются на Chrome
и последнюю версию соответственно.
BUILD_NAME
и TEST_NAME
— кастомные имена для сборки и теста на LambdaTest. Эти идентификаторы облегчают поиск и отслеживание тестов на панели LambdaTest, особенно при запуске нескольких тестов. Это окружение настраивает Python 3.9 с Chrome, используя последнюю версию браузера.
Для py39-firefox
BROWSER_NAME
устанавливается на Firefox
, а BROWSER_VERSION
настраивается на использование последней версии. BUILD_NAME
и TEST_NAME
— кастомные идентификаторы для удобного отслеживания на LambdaTest. В этом окружении используется Python 3.9 с Firefox, поэтому тесты также проверяются на этой конфигурации браузера.
В py311-chrome
параметры BROWSER_NAME
и BROWSER_VERSION
настроены на Chrome последней версии. BUILD_NAME
и TEST_NAME
— это уникальные идентификаторы для сборки и теста на LambdaTest.
Это окружение задает Python 3.11 с Chrome, покрывая дополнительную версию Python.
Для py311-firefox
параметры BROWSER_NAME
и BROWSER_VERSION
установлены на Firefox последней версии. BUILD_NAME
и TEST_NAME
— это кастомные имена для конкретного тестового окружения.
Реализация (test_tox_sample.py
):
lt_options = { "user": os.getenv("LT_USERNAME"), "accessKey": os.getenv("LT_ACCESS_KEY"), "build": os.getenv("BUILD_NAME", "Default Build"), "name": os.getenv("TEST_NAME", "Default Test"), "platformName": os.getenv("PLATFORM_NAME", "Windows 11"), "browserName": os.getenv("BROWSER_NAME", "Chrome"), "browserVersion": os.getenv("BROWSER_VERSION", "latest"), "selenium_version": os.getenv("SELENIUM_VERSION", "latest") } def generate_email(): numbers = ''.join([str(random.randint(0, 9)) for _ in range(8)]) email = f"maria-costa-{numbers}@example.com" return email @pytest.fixture def browser(): web_driver = webdriver.ChromeOptions() if lt_options["browserName"].lower() == "chrome" else webdriver.FirefoxOptions() web_driver.set_capability('LT:Options', lt_options) driver = webdriver.Remote( command_executor="https://hub.lambdatest.com/wd/hub", options=web_driver ) driver.maximize_window() yield driver driver.quit() def test_create_account(browser): browser.get("https://ecommerce-playground.lambdatest.io/index.php?route=account/register") browser.find_element(By.ID, "input-firstname").send_keys("Maria") time.sleep(1) browser.find_element(By.ID, "input-lastname").send_keys("Costa") time.sleep(1) browser.find_element(By.ID, "input-email").send_keys(generate_email()) time.sleep(1) browser.find_element(By.ID, "input-telephone").send_keys("+351123456789") time.sleep(1) browser.find_element(By.ID, "input-password").send_keys("987654321") time.sleep(1) browser.find_element(By.ID, "input-confirm").send_keys("987654321") time.sleep(1) browser.find_element(By.XPATH, "//label[@for='input-newsletter-yes']").click() time.sleep(1) browser.find_element(By.XPATH, "//label[@for='input-agree']").click() time.sleep(1) browser.find_element(By.XPATH, "//input[@value='Continue']").click() time.sleep(3) assert browser.title == "Your Account Has Been Created!" time.sleep(1)
Объяснение кода:
Сценарий начинается с импорта необходимых модулей, включая pytest
для тестирования, selenium
для автоматизации браузера и os
для доступа к переменным окружения.
Также импортируется библиотека random
для генерации уникальных адресов электронной почты для каждого теста, что гарантирует отсутствие конфликтов при создании учетных записей. Это необходимо, поскольку автоматизируемый сайт запрещает создавать новые аккаунты с уже использованными электронными адресами.
Словарь lt_options
предназначен для настройки различных параметров, необходимых для LambdaTest. Этот словарь извлекает учетные данные LambdaTest и специфические для теста параметры из переменных окружения, установленных в tox.ini
. Такие поля, как build
, name
и platformName
, помогут организовать и идентифицировать тестовые прогоны в дашборде LambdaTest.
Функция generate_email()
генерирует случайный адрес электронной почты для каждого теста, что гарантирует отсутствие дублирования писем при многократном выполнении тестов.
Добавляя случайные числа к префиксу электронной почты, мы создаем уникальные письма при каждом запуске теста.
Фикстура browser
описывается с помощью декоратора pytest.fixture
для инициализации и настройки Selenium WebDriver для каждого теста. Фикстура browser
извлекает параметры конфигурации LambdaTest из lt_options
и устанавливает capabilities
в зависимости от выбранного браузера.
WebDriver подключается к Grid, используя указанные учетные данные и опции. После настройки сессии WebDriver разворачивается на весь экран для лучшей видимости, и закрывается после завершения выполнения теста.
Функция test_create_account()
автоматизирует процесс создания учетной записи на LambdaTest eCommerce Playground. WebDriver переходит на URL страницы регистрации, где происходит создание аккаунта.
Тестовый скрипт заполняет различные поля в регистрационной форме, используя send_keys
для ввода. Он взаимодействует с чекбоксами для принятия новостной рассылки и правил и условий. Метод click()
имитирует действия пользователя в чекбоксах, для подписки на рассылку и согласия с условиями.
Наконец, тестовый сценарий отправляет форму регистрации, находя и нажимая кнопку «Продолжить». Это действие запускает отправку формы.
Чтобы убедиться в том, что учетная запись была создана успешно, сценарий проверяет, соответствует ли заголовок страницы ожидаемому результату. Утверждение проверяет заголовок полученной страницы.
Если он совпадает с заголовком «Ваш аккаунт создан!», тест пройден. В противном случае тест падает, указывая на то, что создание учетной записи было неудачным.
Чтобы запустить этот тест, выполните приведенную ниже команду:
tox
Этот тестовый набор настроен на запуск в нескольких окружениях, указанных в файле tox.ini
, а именно Python 3.9 и 3.11 с браузерами Chrome и Firefox на LambdaTest.
Чтобы увидеть результаты теста, переходим на панель веб-автоматизации LambdaTest:
Здесь вы можете проконтролировать, как тесты tox выполняются на платформе.
Юзкейсы
Параллельное тестирование
Последовательный запуск тестов в нескольких окружениях может отнимать много времени, особенно в больших тестовых наборах. tox может сокращать время выполнения, позволяя запускать тесты параллельно в разных окружениях.
По умолчанию tox запускает каждое окружение последовательно. Однако tox поддерживает параллельное выполнение окружений, позволяя тестам выполняться одновременно.
Включить параллельное выполнение с помощью флага -p
или -parallel
:
tox -p 4
Эта команда запустит тесты в четырех окружениях одновременно, что значительно сокращает общее время выполнения, особенно для тестов нескольких браузеров в Selenium.
Для окружений с большим количеством конфигураций или тест-кейсов вы можете позволить tox автоматически определять количество доступных процессоров, выполнив следующую команду:
tox -p auto
Это позволит tox задействовать все доступные ядра процессора, оптимизируя производительность и время выполнения тестов, особенно в CI-конвейерах или на крупных проектах.
Оптимизация времени выполнения теста
Есть еще несколько способов оптимизировать время выполнения тестов при работе с tox и Selenium:
- Распараллеливание браузеров с помощью Selenium Grid: при выполнении тестов можно использовать Selenium Grid для распараллеливания тестов на нескольких экземплярах браузера или даже на удаленных машинах. Это можно сделать в сочетании с настройкой параллельных окружений, предлагаемой tox для дополнительного ускорения.
- Повторное использование окружений: по умолчанию tox создает окружения заново, но если ваши зависимости меняются нечасто, вы можете указать tox пропустить создание и установку окружения с помощью опции
-skip-missing-interpreters
илиskip_install
. Это может значительно сократить время на повторную установку зависимостей, особенно в CI-системах.
Кастомизация окружений
При использовании Selenium + Python вам может потребоваться создание кастомных окружений для различных браузеров, настроек или этапов процесса разработки (например, регрессионных и дымовых тестов).
tox обеспечивает гибкость в описании кастомных окружений, что позволяет эффективнее организовать тесты.
Создание кастомного тестового окружения
Типичный проект в Selenium включает в себя запуск тестов на разных браузерах или разных версиях этих браузеров. tox позволяет создавать кастомные окружения для каждого сценария, описывая их в файле tox.ini
:
[tox] envlist = py39-chrome, py39-firefox, py39-headless [testenv] deps = pytest selenium commands = pytest --driver={env:SELENIUM_DRIVER:chrome} --headless={env:SELENIUM_HEADLESS:false} [testenv:py39-chrome] setenv = SELENIUM_DRIVER=chrome commands = pytest --driver chrome [testenv:py39-firefox] setenv = SELENIUM_DRIVER=firefox commands = pytest --driver firefox [testenv:py39-headless] setenv = SELENIUM_DRIVER=chrome SELENIUM_HEADLESS=true commands = pytest --driver chrome --headless
В этой конфигурации:
- Окружение
py39-chrome
запускает тесты в Chrome. - Окружение
py39-firefox
запускает тесты в Firefox. - Окружение
py39-headless
запускает тесты в режиме безголового Chrome, что полезно для CI, где вам не нужен кастомный интерфейс браузера.
Эти окружения можно запускать по отдельности, что позволяет выполнять тесты с определенными настройками без многократного изменения командной строки.
Использование маркеров окружения и факторов
Система факторов tox позволяет дополнительно уточнять окружение на основе определенных параметров. Это полезно при работе с несколькими конфигурациями Selenium, версиями браузеров или операционных систем.
Вот пример, в котором используются факторы для тестирования различных версий драйверов Chrome и Firefox:
[tox] envlist = py39-{chrome80,chrome90,firefox75,firefox85} [testenv] deps = chrome80: selenium==4.0.0 chrome90: selenium==4.0.0 firefox75: selenium==4.0.0 firefox85: selenium==4.0.0 commands = pytest --driver={env:SELENIUM_DRIVER} --driver-version={env:DRIVER_VERSION} [testenv:py39-chrome80] setenv = SELENIUM_DRIVER=chrome DRIVER_VERSION=80 [testenv:py39-chrome90] setenv = SELENIUM_DRIVER=chrome DRIVER_VERSION=90 [testenv:py39-firefox75] setenv = SELENIUM_DRIVER=firefox DRIVER_VERSION=75 [testenv:py39-firefox85] setenv = SELENIUM_DRIVER=firefox DRIVER_VERSION=85
В этой конфигурации используются маркеры окружения для тестирования различных версий драйверов Chrome и Firefox. В зависимости от потребностей тестирования, вы можете расширить этот подход, чтобы включить больше браузеров или версий.
Интеграция с другими инструментами и фреймворками
Интеграция tox в более широкий процесс тестирования и разработки может значительно повысить эффективность, особенно когда речь идет о фреймворках непрерывной интеграции и тестирования, таких как pytest и unittest.
Интеграция tox с инструментами непрерывной интеграции (CI)
tox легко интегрируется с большинством инструментов CI, обеспечивая автоматизированное тестирование в различных окружениях с минимальными изменениями.
Он также упрощает процесс параллельного выполнения тестов в нескольких конфигурациях, облегчая создание надежных тестовых матриц, которые можно автоматизировать в инструментах CI.
Использование tox с фреймворками тестирования Python
tox часто используется с pytest, но он совместим и с другими фреймворками тестирования на Python, такими как unittest.
Вот пример интеграции фреймворка unittest в проект Selenium:
[testenv] deps = selenium unittest2 commands = python -m unittest discover -s tests
В этой установке tox будет запускать unittest для обнаружения и выполнения тестов из каталога tests
. tox может быть адаптирован под предпочитаемый вами фреймворк тестирования.
Лучшие практики настройки tox
Следование лучшим практикам оптимизации конфигурации должно помочь вашему проекту плавно масштабироваться.
- При увеличении вашего конфиг-файла
tox.ini
важно упорядочить его, для удобства чтения и сопровождения. Используйте комментарии для объяснения неочевидных конфигураций, и логически разделяйте секции.
Например, в приведенном ниже фрагменте кода использование комментариев и группировка логически связанных разделов помогают быстро понять назначение каждой конфигурации.
[tox] # List of all environments to test across different versions and configurations envlist = py37, py38, py39, lint, docs [testenv] # Base dependencies for all test environments deps = pytest commands = pytest [testenv:lint] # Linting environment to check code quality deps = flake8 commands = flake8 myproject [testenv:docs] # Environment for building documentation deps = sphinx commands = sphinx-build -b html docs/ docs/_build/
- Если вы работаете с зависимостями, которые часто обновляются, избегайте жесткого кодирования версий, если это не требуется явно. Вместо этого укажите минимальную версию или диапазон совместимости, что позволит вашим окружениям использовать новые, совместимые версии без вашего вмешательства.
[testenv] deps = pytest>=6.0 selenium>=3.0,<4.0
- Если у вас есть несколько окружений с общими зависимостями или командами, используйте раздел [
testenv
] в качестве базовой конфигурации, чтобы избежать дублирования настроек.
Тогда каждое конкретное окружение сможет отменить только то, что ему необходимо. Это упрощает обслуживание конфигурации и уменьшает количество ошибок при обновлениях.
[tox] envlist = py38, py39, lint [testenv] deps = pytest commands = pytest [testenv:py38] basepython = python3.8 [testenv:py39] basepython = python3.9 [testenv:lint] deps = flake8 commands = flake8 myproject
- tox позволяет определять переменные окружения в файле
tox.ini
, что делает возможным динамическую настройку конфигураций в зависимости от внешних условий.
Например, вам может понадобиться включить дополнительные отчеты о тестировании в CI-окружениях:
[testenv] setenv = CI_ENVIRONMENT = {env:CI_ENVIRONMENT:false} deps = pytest commands = pytest --junitxml=reports/junit.xml
Здесь параметр CI_ENVIRONMENT
может быть установлен в зависимости от того, запускается ли tox в CI-конвейере, и вы можете настроить команды на основе этой переменной, если это необходимо.
- tox пересоздает окружение при каждом запуске, но если зависимости не изменились, пересоздание окружения может создать излишние сущности.
- Можете использовать опцию
skip_install
в окружениях, где установка пакетов не требуется, или использовать опцию-notest
, чтобы пропустить выполнение теста, если вы просто проверяете настройку окружения. - В CI-инструментах кэширование зависимостей между сборками может избавить tox от необходимости каждый раз переустанавливать их. Например, в GitHub Actions можно кэшировать каталог
~/.tox
, чтобы сохранять tox-окружения между сборками, сокращая время установки. - В случаях, когда важна быстрая обратная связь, например во время разработки, подумайте о создании «быстрого» окружения, содержащего только основные зависимости. Это позволит быстро получать обратную связь по основной функциональности, не дожидаясь установки всех зависимостей.
- tox работают с изолированными виртуальными окружениями. Не полагайтесь на глобально установленные пакеты Python, так как это может привести к неожиданным проблемам и затруднить последовательное воспроизведение окружений.
- Избегайте дублирования одних и тех же зависимостей в нескольких окружениях, что может привести к беспорядку и проблемам с обслуживанием. Используйте базовые секции конфигурации и факторы, чтобы уменьшить избыточность.
- Жестко закодированные пути могут вызвать проблемы при переносе Python-проектов между различными системами или CI-конвейерами. По возможности используйте относительные пути и учитывайте переменные окружения для любых системных конфигураций.
- Некоторые тесты могут полагаться на внешние сервисы или базы данных, что может усложнить конфигурацию и замедлить выполнение тестов. Используйте мокированные сервисы или настройте тесты так, чтобы они выполнялись только в тех окружениях, где сервис доступен, например в CI.
Известные проблемы
- Ошибка Environment Not Found: Эта ошибка возникает, когда в системе отсутствует указанный интерпретатор Python. Например, если вы указали
envlist = py37
, но Python 3.7 не установлен, tox не сможет создать это окружение. Используйте опциюskip_missing_interpreters
в секции [tox
], чтобы пропустить недоступные интерпретаторы. - Тестовая команда не распознана: Эта проблема возникает, когда tox пытается запустить команду, которая не установлена в виртуальном окружении. Убедитесь, что все зависимости перечислены в разделе
deps
в файлеtox.ini
, чтобы tox устанавливал их перед запуском команд. - Ошибки отсутствия пакетов: Если возникают ошибки, связанные с отсутствующими пакетами, проверьте, перечислены ли эти пакеты в
deps
. Зависимости в файлахrequirements.txt
также можно указать с помощью команды-r requirements.txt
, но помните о файлах requirements.txt, содержащих специфические для системы или сложные зависимости, которые могут потребовать альтернативных методов установки.
Некоторые зависимости или команды могут вести себя по-разному в различных операционных системах (например, Windows и Linux). Вы можете указать конфигурацию для конкретной ОС в tox:
[testenv] deps = pytest commands = linux: pytest --junitxml=reports/linux-results.xml windows: pytest --junitxml=reports/windows-results.xml
В чем разница между pytest и tox?
pytest — фреймворк для написания и выполнения тестов, а tox — инструмент для автоматизации тестирования в нескольких окружениях. tox управляет зависимостями и обеспечивает совместимость.