PyTest
Introduction | |
Example | |
Структура проекта | |
Тестирование проверки аргументов на тип | |
Запуск unittest тестов | |
Добавить PyTest в PyCharm | |
Похожие статьи |
Введение
Pytest поддерживает тесты, созданные с
unittest
.
Главное преимущество Pytest заключается в особенностях написания TestCase.
TestCase в pytest — это серия функций в файле Python,
которые начинаются с имени test_.
У Pytest есть и другие отличительные особенности:
- поддержка встроенного оператора assert (не нужно использовать специальные методы self.assert);
- поддержка фильтрации;
- возможность перезапуска, начиная с последнего неудачного теста;
- экосистема из сотен плагинов, расширяющих функциональность.
Написание теста TestSum в pytest выглядит так:
def test_sum():
assert sum([1, 2, 3]) == 6, "Should be 6"
def test_sum_tuple():
assert sum((1, 2, 2)) == 6, "Should be 6"
Здесь удалены базовый класс TestCase и любое использование классов в принципе, а также точка входа с командной строки. Как обычно, дополнительная информация представлена на сайте Pytest.
Пример без IDE
Простейший пример в консоле
Linux
Нужно подготовить окружение и создать два файла - с кодом и тестом для этого кода.
Файл с кодом можно назвать как угодно - желательно с маленькой буквы и именем несовпадающим с зарезервированными.
Файл с тестом обычно называют также но с префиксом test_ или реже постфиксом _test
mkdir /home/$(whoami)/python/pytest/qa
cd /home/$(whoami)/python/pytest/qa
python -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip
python -m pip install pytest
touch psum.py test_psum.py
В файле psum.py напишите простую функцию, например сложение
def add(x, y): return x + y
А в файле test_psum.py будет тест для этой функции
from psum import add def test_psum(): assert add(2, 3) == 5, "Should be 5"
Чтобы запустить тест нужно выполнить
pytest test_psum.py
================================================= test session starts ================================================== platform linux -- Python 3.9.5, pytest-7.0.1, pluggy-1.0.0 rootdir: /home/andrei/python/pytest/qa collected 1 item test_psum.py . [100%] ================================================== 1 passed in 0.01s ===================================================
Если функция вернёт результат отличный от ожидаемого, например, в случае ошибки в самом тесте
assert add(2, 3) == 999, "Should be 999"
pytest test_psum.py
================================================= test session starts ================================================== platform linux -- Python 3.9.5, pytest-7.0.1, pluggy-1.0.0 rootdir: /home/andrei/python/pytest/qa collected 1 item test_psum.py F [100%] ======================================================= FAILURES ======================================================= ______________________________________________________ test_psum _______________________________________________________ def test_psum(): > assert add(2, 3) == 999, "Should be 999" E AssertionError: Should be 999 E assert 5 == 999 E + where 5 = add(2, 3) test_psum.py:4: AssertionError =============================================== short test summary info ================================================ FAILED test_psum.py::test_psum - AssertionError: Should be 999 ================================================== 1 failed in 0.02s ===================================================
Структура проекта с тестами на PyTest
Как только проект перерастает микроскопический размер держать тесты в одной директории с кодом становится неудобно
Предположим, что код проекта лежит в директории app можно переложить файл с тестом test_psum.py в поддиректорию tests
app ├── psum.py ├── __pycache__ │ ├── psum.cpython-39.pyc │ └── test_psum.cpython-39-pytest-7.0.1.pyc ├── tests │ ├── __pycache__ │ └── test_psum.py └── venv ├── bin ├── include ├── lib ├── lib64 -> lib └── pyvenv.cfg
Если теперь запустить тест из директории app то pytest поймёт как импортировать psum
python -m pytest tests/test_psum.py
Если запустить этот же тест прямо из директории tests - появится ошибка ImportError while importing test module
Тестирование проверки аргументов на тип
Демонстрацю применения PyTest часто начинают с функций сложения или умножения.
Например
# Code def prod(a, b): return a * b
# Test from prod import prod def test_prod(): res = prod(3, 4) assert res == 12
python -m pytest tests/test_prod.py
Эта функция подразумевает использование чисел. Но валидации аргументов нет.
С помощью
добавим валидацию и напишем тест.
# prod.py def prod(a, b): if not all( map(lambda p: isinstance(p, (int, float)), (a, b)) ): raise TypeError("Not valid argument data type") print("prod.py: Valid arguments") return a * b
# test_prod.py import pytest from prod import prod def test_prod(): res = prod(3, 4) assert res == 12 def test_arguments(): try: # Заведомо неправильный тип данных должен быть пойман # "" is a string and should not be accepted res = prod("", 4) except TypeError as err: # if TypeError is caught pass else: print("test_prod.py: Invalid argument is not caught") pytest.fail() # assert False
Вместо pytest.fail() можно использовать assert False, тогде и импортировать pytest необязательно
python -m pytest -v tests/test_prod.py
================================ test session starts ================================ platform linux -- Python 3.9.5, pytest-7.0.1, pluggy-1.0.0 -- /home/andrei/python/pytest/otus/venv/bin/python cachedir: .pytest_cache rootdir: /home/andrei/python/pytest/app collected 2 items tests/test_prod.py::test_prod PASSED [ 50%] tests/test_prod.py::test_arguments PASSED [100%] ================================= 2 passed in 0.01s =================================
Если тест сломается PyTest выдаст следующий результат
================================ test session starts ================================ platform linux -- Python 3.9.5, pytest-7.0.1, pluggy-1.0.0 -- /home/andrei/python/pytest/otus/venv/bin/python cachedir: .pytest_cache rootdir: /home/andrei/python/pytest/app collected 2 items tests/test_prod.py::test_prod PASSED [ 50%] tests/test_prod.py::test_arguments FAILED [100%] ===================================== FAILURES ====================================== __________________________________ test_arguments ___________________________________ def test_arguments(): try: # "" is a string and should not be accepted res = prod(3, 4) except TypeError as err: # if TypeError is caught pass else: print("test_prod.py: Invalid argument is not caught") > pytest.fail() E Failed tests/test_prod.py:19: Failed ------------------------------- Captured stdout call -------------------------------- prod.py: Valid arguments test_prod.py: Invalid argument is not caught ============================== short test summary info ============================== FAILED tests/test_prod.py::test_arguments - Failed ============================ 1 failed, 1 passed in 0.02s ============================
unittest из PyTest
Если на проекте уже есть тесты, созданные на
unittest
можно их не переписывать - PyTest поймёт синтаксис unittest
Рассмотрим
проверку решения квадратного уравнения на unittest
Если запустить эти же тесты с помощью PyTest
python -m pytest -v tests/test_quadratic.py
================================================== test session starts =================================================== platform linux -- Python 3.9.5, pytest-7.0.1, pluggy-1.0.0 -- /home/andrei/python/unittest/app/venv/bin/python cachedir: .pytest_cache rootdir: /home/andrei/python/unittest/app collected 5 items tests/test_quadratic.py::TestQuadratic::test_raises_type_error PASSED [ 20%] tests/test_quadratic.py::TestQuadratic::test_result_is_tuple PASSED [ 40%] tests/test_quadratic.py::TestQuadratic::test_single_root PASSED [ 60%] tests/test_quadratic.py::TestQuadratic::test_two_roots PASSED [ 80%] tests/test_quadratic.py::TestQuadratic::test_zero_a_and_b PASSED [100%] =================================================== 5 passed in 0.01s ====================================================
Добавить PyTest в Pycharm
Чтобы добавить PyTest в PyCharm воспользуйтесь следующей инструкцией
Settings (Ctrl + Alt + S) → Tools → Python Integrated Tools → Default test runner:
Выбрать pytest. Если он ещё не был добавлен появится предупреждение и кнопка Fix.

Нужно нажать кнопку Fix
Внизу главного экрана настроек появится сообщение
Installing package 'pytest'
Дождитесь когда оно сменится сообщением об успешной установке и с экрана исчезнет предупреждение.

Тестирование | |
Python |