PyTest

Содержание
Introduction
Example
Структура проекта
Тестирование проверки аргументов на тип
Запуск unittest тестов
Добавить PyTest в PyCharm
Похожие статьи

Введение

Pytest поддерживает тесты, созданные с unittest .

Главное преимущество Pytest заключается в особенностях написания TestCase.

TestCase в pytest — это серия функций в файле Python, которые начинаются с имени test_.

У Pytest есть и другие отличительные особенности:

Написание теста 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.

Добавить PyTest в PyCharm изображение с сайта www.aredel.com
PyTest не найден

Нужно нажать кнопку Fix

Внизу главного экрана настроек появится сообщение

Installing package 'pytest'

Дождитесь когда оно сменится сообщением об успешной установке и с экрана исчезнет предупреждение.

Добавить PyTest в PyCharm изображение с сайта www.aredel.com
PyTest как default test runner

Article author: Andrei Olegovich

Похожие статьи
Тестирование
Python

Search this site

Subscribe to Telegram channel @aofeed to follow new articles and updates to old ones

Go to channel

@aofeed

Ask a question in the Telegram group

@aofeedchat

Contacts and cooperation:
I recommend our hosting beget.ru
Write to info@urn.su, info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: