Библиотека pytest
Скажем , мы тестируем функцию добавления в projectroot/module/code.py :
# projectroot/module/code.py def add(a, b): return a + b
Код тестирования
Мы создаем тестовый файл в projectroot/tests/test_code.py .Файл должен начинаться с test_ , чтобы быть признанным в качестве файла тестирования.
# projectroot/tests/test_code.py from module import code def test_add(): assert code.add(1, 2) == 3
Запуск теста
Из projectroot мы просто запустить py.test :
# ensure we have the modules $ touch tests/__init__.py $ touch module/__init__.py $ py.test ================================================== test session starts =================================================== platform darwin — Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 rootdir: /projectroot, inifile: collected 1 items tests/test_code.py . ================================================ 1 passed in 0.01 seconds ================================================
Неудачные тесты
Неудачный тест предоставит полезный вывод о том, что пошло не так:
Что такое PyTest Fixture и когда она полезны
# projectroot/tests/test_code.py from module import code def test_add__failing(): assert code.add(10, 11) == 33
$ py.test ================================================== test session starts =================================================== platform darwin — Python 2.7.10, pytest-2.9.2, py-1.4.31, pluggy-0.3.1 rootdir: /projectroot, inifile: collected 1 items tests/test_code.py F ======================================================== FAILURES ======================================================== ___________________________________________________ test_add__failing ____________________________________________________ def test_add__failing(): > assert code.add(10, 11) == 33 E assert 21 == 33 E + where 21 = (10, 11) E + where = code.add tests/test_code.py:5: AssertionError ================================================ 1 failed in 0.01 seconds ================================================
Введение в тестовые приспособления
Более сложные тесты иногда требуют настройки перед запуском кода, который вы хотите протестировать. Это можно сделать в самой тестовой функции, но в результате вы получаете большие тестовые функции, которые делают так много, что трудно сказать, где остановка установки и начало теста. Вы также можете получить много повторяющихся кодов установки между различными функциями тестирования.
Наш кодовый файл:
# projectroot/module/stuff.py class Stuff(object): def prep(self): self.foo = 1 self.bar = 2
Наш тестовый файл:
# projectroot/tests/test_stuff.py import pytest from module import stuff def test_foo_updates(): my_stuff = stuff.Stuff() my_stuff.prep() assert 1 == my_stuff.foo my_stuff.foo = 30000 assert my_stuff.foo == 30000 def test_bar_updates(): my_stuff = stuff.Stuff() my_stuff.prep() assert 2 == my_stuff.bar my_stuff.bar = 42 assert 42 == my_stuff.bar
Это довольно простые примеры, но если наш Stuff объекта нужно намного больше настроек, это будет получить громоздким. Мы видим, что между нашими тестами есть некоторый дублированный код, поэтому давайте сначала соберем его в отдельную функцию.
PYTHON PYTEST. ОСНОВЫ. 1 ЧАСТЬ
# projectroot/tests/test_stuff.py import pytest from module import stuff def get_prepped_stuff(): my_stuff = stuff.Stuff() my_stuff.prep() return my_stuff def test_foo_updates(): my_stuff = get_prepped_stuff() assert 1 == my_stuff.foo my_stuff.foo = 30000 assert my_stuff.foo == 30000 def test_bar_updates(): my_stuff = get_prepped_stuff() assert 2 == my_stuff.bar my_stuff.bar = 42 assert 42 == my_stuff.bar
Это выглядит лучше , но у нас еще есть my_stuff = get_prepped_stuff() вызов захламление наши тестовые функции.
py.test светильники на помощь!
Светильники являются гораздо более мощными и гибкими версиями функций настройки теста. Они могут сделать намного больше, чем мы используем здесь, но мы сделаем это по одному шагу за раз.
Теперь мы должны обновить тестовые функции, чтобы они использовали прибор. Это делается путем добавления параметра к их определению, который точно совпадает с именем прибора. Когда py.test выполняется, он запускает прибор перед запуском теста, а затем передает возвращаемое значение прибора в тестовую функцию через этот параметр. (Обратите внимание , что светильники не нужно возвращать значение, они могут сделать другие настройки вещи вместо того, чтобы , как вызов внешнего ресурса, устраивая вещи в файловой системе, помещая значения в базе данных, независимо от тестов нужно для установки)
def test_foo_updates(prepped_stuff): my_stuff = prepped_stuff assert 1 == my_stuff.foo my_stuff.foo = 30000 assert my_stuff.foo == 30000 def test_bar_updates(prepped_stuff): my_stuff = prepped_stuff assert 2 == my_stuff.bar my_stuff.bar = 42 assert 42 == my_stuff.bar
Теперь вы можете понять, почему мы назвали его существительным. но my_stuff = prepped_stuff линия довольно много бесполезной, так что давайте просто использовать prepped_stuff непосредственно вместо этого.
def test_foo_updates(prepped_stuff): assert 1 == prepped_stuff.foo prepped_stuff.foo = 30000 assert prepped_stuff.foo == 30000 def test_bar_updates(prepped_stuff): assert 2 == prepped_stuff.bar prepped_stuff.bar = 42 assert 42 == prepped_stuff.bar
Теперь мы используем светильники! Мы можем пойти дальше, изменив область действия прибора (чтобы он запускался только один раз для каждого тестового модуля или сеанса выполнения набора тестов, а не один раз для каждой тестовой функции), создавая приборы, использующие другие приборы, параметризовав прибор (так, чтобы прибор и все тесты с использованием этого прибора выполняются несколько раз, по одному разу для каждого параметра, переданного устройству), приборы, которые считывают значения из вызывающего их модуля . как упоминалось ранее, приборы имеют гораздо большую мощность и гибкость, чем обычная функция настройки.
Очистка после испытаний.
Допустим, наш код вырос и наш объект Stuff теперь нуждается в специальной очистке.
# projectroot/module/stuff.py class Stuff(object): def prep(self): self.foo = 1 self.bar = 2 def finish(self): self.foo = 0 self.bar = 0
Мы могли бы добавить некоторый код для вызова очистки внизу каждой тестовой функции, но приспособления предоставляют лучший способ сделать это. Если добавить функцию к арматуре и зарегистрировать его в качестве финализации, код в функции финализатора будет вызван после испытания с помощью прибора выполняется. Если область действия прибора больше, чем одна функция (например, модуль или сеанс), финализатор будет выполнен после завершения всех тестов в области, то есть после завершения работы модуля или в конце всего сеанса выполнения теста. ,
Использование функции финализатора внутри функции может быть довольно сложно понять на первый взгляд, особенно если у вас есть более сложные приборы. Вместо этого вы можете использовать выход приспособление , чтобы сделать то же самое с более читаемом потоком выполнения. Единственное отличие в том , что вместо того , чтобы использовать return мы используем yield на части прибора , где установка делаются и контроль должен идти к тестовой функции, затем добавьте весь код очистки после yield .Мы также украсить его как yield_fixture так , что py.test знает , как справиться с этим.
И это завершает вступление к тестовым приспособлениям!
Для получения дополнительной информации см официальной py.test арматуры документация и документация арматуре официального выхода
Источник: www.codecamp.ru
pytest 7.2.0
The pytest framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries.
An example of a simple test:
To execute it:
$ pytest ============================= test session starts ============================= collected 1 items test_sample.py F ================================== FAILURES =================================== _________________________________ test_answer _________________________________ def test_answer(): > assert inc(3) == 5 E assert 4 == 5 E + where 4 = inc(3) test_sample.py:5: AssertionError ========================== 1 failed in 0.04 seconds ===========================
Due to pytest ’s detailed assertion introspection, only plain assert statements are used. See getting-started for more examples.
Features
- Detailed info on failing assert statements (no need to remember self.assert* names)
- Auto-discovery of test modules and functions
- Modular fixtures for managing small or parametrized long-lived test resources
- Can run unittest (or trial), nose test suites out of the box
- Python 3.7+ or PyPy3
- Rich plugin architecture, with over 850+ external plugins and thriving community
Documentation
For full documentation, including installation, tutorials and PDF documents, please see https://docs.pytest.org/en/stable/.
Bugs/Requests
Please use the GitHub issue tracker to submit bugs or request features.
Changelog
Consult the Changelog page for fixes and enhancements of each version.
Support pytest
Open Collective is an online funding platform for open and transparent communities. It provides tools to raise money and share your finances in full transparency.
It is the platform of choice for individuals and companies that want to make one-time or monthly donations directly to the project.
See more details in the pytest collective.
pytest for enterprise
Available as part of the Tidelift Subscription.
The maintainers of pytest and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use.
Security
pytest has never been associated with a security vulnerability, but in any case, to report a security vulnerability please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure.
License
Copyright Holger Krekel and others, 2004.
Distributed under the terms of the MIT license, pytest is free and open source software.
Источник: pypi.org
Pytest — тестирование приложений в Python 3
Обзор мощной библиотеки для тестирования кода Pytest.
Введение
Вы знали, что тестирование кода приносит множество преимуществ, включая повышение уверенности в его функционировании и уменьшение регрессий? Если нет, то читайте дальше!
Написание и ведение тестов требует некоторой дополнительной работы, и именно поэтому я хочу максимально использовать все инструменты.
Python действительно предоставляет встроенные инструменты, такие как unittest, для поддержки тестирования, но он включает в себя написание большого количества шаблонного кода. Он также имеет ограниченную возможность повторного использования компонентов (или приспособлений в PyTest). Поэтому я буду тестировать приложения Python с помощью Pytest вместо других инструментов. Pytest также является самым популярным инструментом среди других альтернатив.
Примечание: В этой статье я буду использовать Python 3.
Почему Pytest?
Pytest — одна из самых популярных библиотек, посвященных модульному и функциональному тестированию. Но что делает её такой популярной? Вот ответ:
- Меньше шаблонности.
- Установочный код можно использовать повторно с помощью приспособлений.
- Фильтрация тестов во время выполнения (для одновременного выполнения только определенного набора тестов).
- Параметризация тестов (предоставление различных входных значений одному и тому же тесту, позволяющее тестировать различные сценарии с использованием одного теста).
- Архитектура на основе плагинов, обеспечивающая гибкость и более широкое внедрение.
- Возможность параллельно выполнять тесты.
Установка Pytest
Pytest — это библиотека, которую нам нужно будет добавить в наш проект. Как известно, я всегда выбираю для программирования виртуальную среду и работаю исключительно в ней:
$ mkdir pytest-demo $ cd pytest-demo $ python3 -m venv .venv $ source .venv/bin/activate
А потом я устанавливаю Pytest:
$ python -m pip install pytest
Это позволит включить команду pytest в нашей установочной среде. Установка завершает наш первый шаг в тестировании приложений Python с помощью Pytest. Давайте перейдем к следующему шагу.
Соглашения об именовании
Как и в любом тестовом фреймворке, в Pytest есть несколько мест, где он автоматически ищет тестовые файлы.
Имя файла должно начинаться с «test» или заканчиваться «test.py».
Определенные тестовые функции должны начинаться с «test_». Методы, которые не следуют этому соглашению, не выполняются. Чтобы увидеть, какие тесты будут выполняться без их запуска, мы можем использовать:
pytest —collect-only
А чтобы выполнить все тесты в нашем каталоге pytest-demo, я запускаю:
pytest pytest-demo
Если я не укажу каталог, Pytest будет работать в текущем каталоге по умолчанию. Или я могу указать отдельные файлы, если я захочу это сделать.
Или, если я хочу игнорировать каталог (например, виртуальную среду), то я могу использовать:
pytest —ignore .venv
Настройка кода
Теперь, когда вы знаете основы, давайте настроим код, который мы будем тестировать. Мы можем использовать сложный блок кода и написать несколько тестовых случаев вокруг него, но этот пост больше связан с Pytest, чем с написанием тестовых случаев. Поэтому мы будем придерживаться простой задачи сложения и вычитания:
# calculator.py def add(firstNumber, secondNumber): return firstNumber + secondNumber def subtract(firstNumber, secondNumber): return firstNumber — secondNumber
Тестирование приложений
Теперь, когда у нас есть наш минимальный фрагмент кода, мы можем начать с нашего основного теста. Мы будем делать расчет 2 + 1 = 3. Для этого я определю наш тест как:
# calculator_test.py from calculator import add def test_add(): firstNumber = 2 secondNumber = 1 assert add(firstNumber, secondNumber) == 3
Ключевое слово assert сравнивает два значения, которые оно получает, и возвращает True или False на основе их равенства. Мы также можем иметь подробные утверждения, которые могут быть полезны при отладке. Они могут быть записаны как:
assert True == False, «This is a demo with a failed assertion and a detailed message.»
Подробные утверждения могут быть полезны для целей отладки.
Наконец, мы можем запустить наш тест с помощью команды:
pytest
И вот, у нас есть наш первый успешный тест!
Точно так же мы можем написать тест и для нашего метода вычитания:
# calculator_test.py from calculator import add def test_add(): firstNumber = 2 secondNumber = 1 assert subtract(firstNumber, secondNumber) == 1
Уровень отладки Pytest
Я могу передать параметр во время выполнения тестов, чтобы увеличить/уменьшить многословность выходных данных, генерируемых Pytest. Доступны следующие варианты:
- v: увеличивает многословность.
- q: более тихий вывод.
- r: сводка тестов.
- rp: сводка пройденных тестов.
- rp: сводка неудачных тестов.
Заключение
Это было краткое введение в тестирование приложений Python с помощью Pytest. Если вам понравилась статья напиши об этом в комментариях или почитайте другие похожие статьи на тему Python.
Источник: egorovegor.ru
Фреймворк pytest в Python, тестирование кода.
Фреймворк pytest позволяет легко писать небольшие, удобочитаемые тесты и может масштабироваться для поддержки сложного функционального тестирования приложений и библиотек.
Для работы pytest требуется: Python 3.7+ или PyPy3.
Установка модуля pytest в виртуальное окружение.
Модуль pytest размещен на PyPI, поэтому установка относительно проста.
# создаем виртуальное окружение, если нет $ python3 -m venv .venv —prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # обновляем `pip` (VirtualEnv):~$ python3 -m pip install -U pip # ставим модуль `pytest` (VirtualEnv):~$ python3 -m pip install -U pytest
Общие сведения о тестировании при помощи pytest
Тесты предназначены для того, чтобы посмотреть на результат поведения кода в определенной ситуации и убедиться, что результат соответствует тому, который ожидается. Поведение нельзя измерить эмпирически, поэтому написание тестов может быть сложной задачей.
Поведение — это то, как некоторая система действует в ответ на конкретную ситуацию и/или действия. Но как именно и почему что-то делается, не так важно, как то, что было сделано.
Можно думать о тесте как о четырех этапах:
- Подготовка.
- Действие.
- Утверждение.
- Очистка.
Подготовка.
ПОДГОТОВКА означает практически все, кроме ДЕЙСТВИЯ. Проще говоря — это подготовка окружения и объектов, которые требуются для проведения ДЕЙСТВИЯ. Это может быть все что угодно: подготовка к инициализации объектов, создание временных каталогов и файлов, запуск/остановку служб, ввод записей в базу данных или даже такие вещи, как определение URL-адреса для запроса, создание некоторых учетных данных для еще не существующего пользователя или просто ожидание завершения какого-либо процесса.
Действие.
ДЕЙСТВИЕ это то, что изменит состояние, которое запускает поведение, подлежащее тестированию. Именно это поведение осуществляет изменение тестируемой системы (SUT) по которому можно судить об устойчивости этой системы. Обычно ДЕЙСТВИЕ принимает форму вызова функции/метода с ПОДГОТОВЛЕННЫМ контекстом для моделирования той или иной ситуации.
Утверждение.
УТВЕРЖДЕНИЕ — это место, где проверяется результирующее состояние тестируемой системы, то есть, что соответствует или не соответствует ожидаемому результату/поведению. Утверждение в тесте — это проведение сравнения полученного состояния во время ДЕЙСТВИЯ с неким, наперед известным/ожидаемым результатом, на основании которого можно судить об устойчивости системы. Например: если итоговая переменная result должна иметь список целых чисел в диапазоне от 0 до 10, то утверждение будет выглядеть следующим образом:
# длинные утверждения не дают сразу понять, # что же здесь хотели проверить assert (isinstance(result, list) and all([isinstance(n, int) for n in result]) and all([0 n 10 for n in result]))
Что бы не писать длинные утверждения, их можно разнести по разным тестовым функциям, которые в свою очередь можно объединить в группу при помощи класса или модуля. Группы тестов помогают использовать одни и те же значения переменных для тестируемой функции/метода. Это поможет избежать передачу параметров для каждого отдельного теста, при тестировании одной и той же функции.
Очистка.
ОЧИСТКА — это то, где тест сам по себе завершает работу, и что бы случайно не повлиять на итоги других тестов, производится очистка ПОДГОТОВЛЕННОГО контекста (если это требуется). Например, удаление тестовых пользователей/записей из баз данных, очистка временных файлов из рабочей директории и т.д.
Очистку можно производить как в самих тестовых функциях, так и в фикстурах.
По своей сути, тест — это этапы ДЕЙСТВИЯ и УТВЕРЖДЕНИЯ, а этап ПОДГОТОВКИ обеспечивает только контекст. Поведение существует между ДЕЙСТВИЕМ и УТВЕРЖДЕНИЕМ.
Общий примеры использования фреймворка pytest .
На базовом уровне, тестовые функции запрашивают необходимые им фикстуры, объявляя их в качестве аргументов.
Когда pytest запускает тест, он просматривает аргументы в сигнатуре этой тестовой функции, а затем ищет фикстуры с теми же именами, что и эти аргументы. Как только pytest находит их, он запускает эти фикстуры, фиксирует то, что они вернули (если возвращают), и передает эти объекты в тестовую функцию в качестве аргументов.
В этом примере test_fruit_salad() «запрашивает» fruit_bowl() (т.е. def test_fruit_salad(fruit_bowl): ), и когда pytest увидит это, он выполнит функцию-фикстуру fruit_bowl и передаст возвращаемый объект в test_fruit_salad в качестве аргумента fruit_bowl .
А так одна фикстура, может запрашивать/взаимодействовать с другой фикстурой:
Передача параметров в тестируемый метод/функцию.
Фреймворк pytest позволяет параметризировать тест на нескольких уровнях:
Для этого создадим необходимые папки и файлы:
# создаем необходимые папки $ mkdir -p ./testing/test_folder # создаем необходимые файлы (они будут пустые) $ touch ./testing/util.py ./testing/test_folder/test_util.py
Далее открываем файл ./testing/util.py и вставляем в него код ниже.
# файл ./testing/util.py def str_to_num(str): «»»Вспомогательная функция: преобразует строку в число»»» if ‘.’ in str and str.replace(‘.’, »).isdigit(): return float(str) elif str.isdigit(): return int(str) def str_to_int_list(str_lst): «»»Тестируемая функция: преобразует список строк в список целых чисел»»» num_list = [] for item in str_lst: n = str_to_num(item) if n is not None: if isinstance(n, float): n = round(n) if 0 n 10: num_list.append(n) return num_list
И наконец открываем файл ./test_folder/test_util.py и вставляем в него код с тестом, который расположен ниже.
Обратите внимание как в файле теста происходит импорт from util import str_to_int_list , хотя файл util.py находится на уровень выше. (подробнее об импорте при тестировании в материале «Интеграция тестов pytest с проектом.»)
Запускаем тесты. Для этого активируем виртуальное окружение, где установлен pytest и затем перейдем в папку ./testing :
# активируем виртуальное окружение $ source .venv/bin/activate # перейдем в папку `./testing` (VirtualEnv) :~$ cd testing # запускаем тест (VirtualEnv) :~/testing$ python3 -m pytest -v
Готово, тесты должны отработать.
Источник: docs-python.ru
Начало работы с Pytest
Pytest называют одним из лучших тестовых фреймворков для Python. Это не удивительно, ведь Pytest прост, масштабируем, и, как порой утверждают, «пайтоничен». С его помощью тест-кейсы пишут как функции, а не классы, плюс существуют всевозможные плагины, позволяющие добавлять параллельный запуск, красивые отчеты и т. п. Что ж, давайте создадим первый тестовый проект на Python и напишем первый тест.
Для начала скачиваем и устанавливаем Python 3. Далее создаем для нашего проекта новую директорию:
При создании нового Python-проекта неплохим решением является создание виртуального окружения для его зависимостей. Что это даст? Ну, к примеру, у ваших проектов, размещенных на одной машине, будут отсутствовать конфликтующие версии пакетов.
Для решения поставленной задачи воспользуемся pipenv:
Теперь можно установить pytest для нашего нового проекта:
Pipenv добавит в проект 2 новых файла: — Pipfile; — Pipfile.lock.
Первый служит для определения требования проекта, второй «блокирует» явные версии, которыми этот проект будет пользоваться. Что касается опции «–dev» в команде выше, то она означает, что пакет pytest станет применяться не для деплоя, а для разработки.
Пишем первый тест
Традиционно тесты размещают в директории tests/. Не будем нарушать эту традицию:
Теперь создадим для первого теста «Пайтон»-модуль с именем test_math.py и сразу добавим следующий код:
Тестам, которые пишутся посредством pytest, как правило, много кода не требуется. Можно сказать, что 2 строчки выше — это уже полноценный тест-кейс, причем он написан как функция, а не как класс. Импорты для этого базового теста не нужны. Вместо кастомных контрольных вызовов применяют нативный оператор контроля Python.
Запускаем тест
Что же, давайте выполним запуск. Для этого поменяем директорию на корневую директорию проекта, а потом вызовем модуль pytest:
Ура, первый тест пройден успешно!
Как же pytest обнаружил наш первый тест? Сделал он это по имени, то есть pytest ищет тест-функции с названием test_* в модулях с названием test_*.py . Причем интересный момент заключается в том, что pytest не требует в тестовых директориях файла __init__.py .
Источник: otus.ru