Приступить к работе¶
Установить pytest
¶
pytest
Требуется: Python 3.7+ или PyPy3.
Выполните следующую команду в командной строке:
pip install -U pytest
Убедитесь, что вы установили правильную версию:
$ pytest --version
pytest 7.2.0
Создайте свой первый тест¶
Создайте новый файл с именем 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-7.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
для проверки ожиданий теста. Advanced assertion introspection в pytest разумно сообщает промежуточные значения выражения assert, так что вы можете избежать множества имен of JUnit legacy methods.
Проведите несколько тестов¶
pytest
запустит все файлы вида test_*.py или *_test.py в текущем каталоге и его подкаталогах. В более общем случае, он следует за standard test discovery rules.
Утверждать, что определенное исключение вызвано¶
Используйте помощник 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
обнаруживает все тесты, следующие за его Conventions for Python test discovery, поэтому он находит обе функции с префиксом 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
предоставляет Builtin fixtures/function arguments для запроса произвольных ресурсов, например, уникального временного каталога:
# 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
Более подробную информацию о работе с временными каталогами можно найти на Temporary directories and files.
Выясните, какие встроенные pytest fixtures существуют для данной команды:
pytest --fixtures # shows builtin and custom fixtures
Обратите внимание, что эта команда опускает фикстуры с ведущими _
, если не добавлена опция -v
.
Продолжить чтение¶
Ознакомьтесь с дополнительными ресурсами pytest, которые помогут вам настроить тесты для вашего уникального рабочего процесса:
«Как вызвать pytest» для примеров вызова командной строки
«Как использовать pytest с существующим набором тестов» для работы с уже существующими тестами
«Как пометить тестовые функции атрибутами» для получения информации о механизме
pytest.mark
«Ссылка на светильники» для обеспечения функциональной основы для ваших тестов
«Написание плагинов» для управления и записи плагинов
«Передовая практика интеграции» для макетов virtualenv и тестовых макетов