Начало работы
Установка pytest
- Выполните следующую команду в командной строке:
pip install -U pytest
- Убедитесь, что установлена правильная версия:
$ pytest --version pytest 9.1.1
Создайте свой первый тест
Создайте новый файл с именем test_sample.py, содержащий функцию и тест:
# content of test_sample.py
def func(x):
return x + 1
def test_answer():
assert func(3) == 5
Тест
$ pytest
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-9.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
collected 1 item
test_sample.py F [100%]
================================= FAILURES =================================
_______________________________ test_answer ________________________________
def test_answer():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:6: AssertionError
========================= short test summary info ==========================
FAILED test_sample.py::test_answer - assert 4 == 5
============================ 1 failed in 0.12s =============================
[100%] показывает общий ход выполнения всех тестовых случаев. После завершения pytest выводит отчет об ошибке, поскольку func(3) не возвращает 5.
Примечание
Для проверки ожидаемых результатов теста можно использовать оператор assert. Интеллектуальный анализ утверждений в pytest позволяет наглядно отобразить промежуточные значения выражения assert, избавляя от необходимости использовать множество унаследованных методов JUnit.
Запуск нескольких тестов
pytest запустит все файлы с именами вида test_*.py или *_test.py в текущем каталоге и его подкаталогах. В более общем случае применяются стандартные правила обнаружения тестов.
Проверка вызова определённого исключения
Используйте вспомогательную функцию raises, чтобы проверить, что некоторый код вызывает исключение:
# content of test_sysexit.py
import pytest
def f():
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
Запустите тестовую функцию в режиме «краткого» вывода:
$ pytest -q test_sysexit.py . [100%] 1 passed in 0.12s
Примечание
Флаг -q/--quiet делает вывод кратким в этом и следующих примерах.
Информацию о том, как указать дополнительные сведения об ожидаемом исключении, см. в разделе Проверки ожидаемых исключений.
Группировка нескольких тестов в классе
По мере того как вы создаёте несколько тестов, может возникнуть необходимость сгруппировать их в класс. pytest позволяет легко создать класс, содержащий несколько тестов:
# content of test_class.py
class TestClass:
def test_one(self):
x = "this"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
pytest обнаруживает все тесты, соответствующие соглашениям об обнаружении тестов Python, поэтому находит обе функции с префиксом test_. Наследовать какой-либо класс не нужно, но не забудьте добавить к имени класса префикс Test, иначе класс будет пропущен. Просто запустите модуль, указав его имя файла:
$ pytest -q test_class.py
.F [100%]
================================= FAILURES =================================
____________________________ TestClass.test_two ____________________________
self = <test_class.TestClass object at 0xdeadbeef0001>
def test_two(self):
x = "hello"
> assert hasattr(x, "check")
E AssertionError: assert False
E + where False = hasattr('hello', 'check')
test_class.py:8: AssertionError
========================= short test summary info ==========================
FAILED test_class.py::TestClass::test_two - AssertionError: assert False
1 failed, 1 passed in 0.12s
Первый тест прошёл, а второй завершился с ошибкой. Промежуточные значения в утверждении позволяют легко понять причину ошибки.
Группировка тестов в классах может быть полезна по следующим причинам:
- Организация тестов
- Общий доступ к фикстурам для тестов только в этом классе
- Применение маркеров на уровне класса, которые автоматически распространяются на все тесты
При группировке тестов в классах важно учитывать, что для каждого теста создаётся отдельный экземпляр класса. Использование одного экземпляра класса для всех тестов серьёзно нарушило бы изоляцию тестов и привело бы к неправильной организации тестирования. Это показано ниже:
# content of test_class_demo.py
class TestClassDemoInstance:
value = 0
def test_one(self):
self.value = 1
assert self.value == 1
def test_two(self):
assert self.value == 1
$ pytest -k TestClassDemoInstance -q
.F [100%]
================================= FAILURES =================================
______________________ TestClassDemoInstance.test_two ______________________
self = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>
def test_two(self):
> assert self.value == 1
E assert 0 == 1
E + where 0 = <test_class_demo.TestClassDemoInstance object at 0xdeadbeef0002>.value
test_class_demo.py:9: AssertionError
========================= short test summary info ==========================
FAILED test_class_demo.py::TestClassDemoInstance::test_two - assert 0 == 1
1 failed, 1 passed in 0.12s
Обратите внимание, что атрибуты, добавленные на уровне класса, являются атрибутами класса, поэтому они будут общими для всех тестов.
Сравнение чисел с плавающей точкой с помощью pytest.approx
pytest также предоставляет ряд утилит, упрощающих написание тестов. Например, можно использовать pytest.approx() для сравнения чисел с плавающей точкой, в которых могут быть небольшие ошибки округления:
# content of test_approx.py
import pytest
def test_sum():
assert (0.1 + 0.2) == pytest.approx(0.3)
Это избавляет от необходимости вручную проверять допустимую погрешность или использовать math.isclose; функция работает со скалярными значениями, списками и массивами NumPy.
Запрос уникального временного каталога для функциональных тестов
pytest предоставляет встроенные фикстуры и аргументы функций для запроса различных ресурсов, например уникального временного каталога:
# content of test_tmp_path.py
def test_needsfiles(tmp_path):
print(tmp_path)
assert 0
Укажите имя tmp_path в сигнатуре тестовой функции, и pytest найдёт и вызовет фабрику фикстуры, чтобы создать ресурс перед вызовом тестовой функции. Перед запуском теста pytest создаёт уникальный для каждого запуска теста временный каталог:
$ pytest -q test_tmp_path.py
F [100%]
================================= FAILURES =================================
_____________________________ test_needsfiles ______________________________
tmp_path = PosixPath('PYTEST_TMPDIR/test_needsfiles0')
def test_needsfiles(tmp_path):
print(tmp_path)
> assert 0
E assert 0
test_tmp_path.py:3: AssertionError
--------------------------- Captured stdout call ---------------------------
PYTEST_TMPDIR/test_needsfiles0
========================= short test summary info ==========================
FAILED test_tmp_path.py::test_needsfiles - assert 0
1 failed in 0.12s
Подробнее об обработке временных каталогов см. в разделе Временные каталоги и файлы.
Узнать, какие встроенные фикстуры pytest доступны, можно с помощью команды:
pytest --fixtures # shows builtin and custom fixtures
Обратите внимание: эта команда не выводит фикстуры, имена которых начинаются с _, если не добавить параметр -v.
Продолжение чтения
Ознакомьтесь с дополнительными ресурсами по pytest, которые помогут настроить тесты в соответствии с вашим рабочим процессом:
- «Как запустить pytest» — примеры запуска из командной строки
- «Как использовать pytest с существующим набором тестов» — работа с уже написанными тестами
- «Как помечать тестовые функции атрибутами» — сведения о механизме
pytest.mark - «Справочник по фикстурам» — создание функциональной основы для тестов
- «Написание плагинов» — управление плагинами и их создание
- «Рекомендации по интеграции» — виртуальные окружения и организация тестов
© 2015–2026 Holger Krekel and pytest-dev team
Licensed under the MIT License.
https://docs.pytest.org/en/stable/getting-started.html