pytest и кастомные аргументы командной строки |
12.09.2023 00:00 |
Автор: Баз Дейкстра (Bas Dijkstra) Недавно меня спросили по email: Не могли бы вы, пожалуйста, предложить хороший пример взятия параметра вроде «URL базового окружения» из интерфейса командной строки и передачи его в каждый тест в наборе на основе pytest? Насколько я знаю, в Java это довольно легко делается. Вот пример командной строки, использующий Maven для запуска тестов и передающий значение http://localhost:8080/api для переменной командной строки env: mvn clean -Denv=http://localhost:8080/api test В вашем коде Java можно затем получить доступ к этой переменной: // 'http://some-default-env.com/api' будет использоваться, как значение по умолчанию, если для env не задано значение Но как сделать это в pytest? И, что еще важнее, как убедиться, что значение, переданное через командную строку, доступно во всех тестах? Ответ: парсер и фикстуры pytest. Разберем пошагово. Регистрация кастомного аргумента командной строки в pytestПервый шаг, который нужно предпринять для получения возможности передать аргументы командной строки в pytest и их использования в тестах – это регистрация нового аргумента командной строки в pytest. Это можно сделать, добавив вот такой сниппет в файл conftest.py, который хранится в корневой папке проекта: def pytest_addoption(parser): Это позволяет нам передавать кастомный аргумент –base-url, когда мы вызываем pytest – к примеру, так: pytest --base-url=http://api.zippopotam.us zip_api_test.py Если аргумент –base-url при вызове pytest отсутствует, будет использоваться значение по умолчанию – http://localhost:8080. Parser тут – это объект, доступный pytest по умолчанию. Его можно использовать для парсинга аргументов командной строки, а также для значений файла .ini. Использование значения аргумента командной строки в наших тестахДалее нам нужно прочитать значение аргумента командной строки и передать его в тесты. Один из самых удобных способов это сделать – это фикстура pytest: @pytest.fixture Эта фикстура считывает значение из аргумента командной строки и возвращает его. Теперь ее можно использовать во всех тестах – например, так: def test_api_endpoint(base_url): Этот тестовый метод использует фикстуру base_url для получения базового URL, переданного через командную строку при вызове pytest (или значение по умолчанию, если оно не было задано в аргументе), для отправки HTTP-запроса к конечной точке с использованием базового URL. Если теперь прогнать наш тест, используя pytest -s zip_api_test.py Он выведет: http://localhost:8080/us/90210 в качестве конечной точки, использующейся для HTTP-запроса, так как мы не задали никакого значения в аргументе base-url командной строки. Если вызвать pytest так: pytest -s --base-url=http://api.zippopotam.us zip_api_test.py Он выведет: http://api.zippopotam.us/us/90210 в качестве конечной точки, использующейся для запроса, демонстрируя, что значение, переданное в аргументе командной строки, было успешно применено. Победа! Расширение подхода для нескольких переменныхНо что, если мы хотим передать несколько переменных? Что, если, помимо базового URL, мы, скажем, хотим передать данные авторизации для наших тестов, чтобы не хранить их в коде тестов? Как я это вижу: возможны два способа решения. В первую очередь в обоих случаях вам нужно зарегистрировать дополнительные аргументы командной строки – например, так: def pytest_addoption(parser): Теперь у нас есть два варианта. Первый: мы храним все значения аргументов командной строки в едином объекте фикстуры – например, так: @pytest.fixture Затем можно использовать эту фикстуру в наших тестах, извлекая значения из словаря в теле тест-метода. Второй вариант: мы создаем отдельную фикстуру для каждого из аргументов командной строки. Это сохраняет фикстуры небольшими, но требует использования нескольких фикстур во всех тестах, что может стать несколько громоздким и не очень хорошо масштабируется. Этот подход, однако, добавляет некоторую гибкость при решении, какую фикстуру использовать в каких тестах. Как и многое другое в жизни, выбор наилучшего подхода зависит от ситуации. В целом я предпочитаю первый вариант. Возможно, есть и третий, о котором я не подумал? Сообщите мне о нем. |