pytest.raises

Введение

В этой статье вы можете познакомиться с применением контекстного менеджера pytest.raises() в PyTest.

Официальная документация

Пример

Рассмотрим проект со следующей оригинальной структурой

cm ├── tests │ ├── __init__.py │ └── test_phonebook.py ├── phonebook.py └── venv

В телефонную книгу можно добавлять имя и номер с помощью .add() и искать с помощью lookup()

# phonebook.py class Phonebook: def __init__(self): self.storage = {} def add(self, name, number): self.storage[name] = number def lookup(self, name): return self.storage[name]

# test_phonebook.py import os import sys ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.append(ROOT) from cm.phonebook import Phonebook def test_look_up_by_name(): phonebook = Phonebook() phonebook.add("Yuri", "1961") result = phonebook.lookup("Yuri") assert result == "1961"

Из родительской к cm директории выполним

python -m pytest -vv .\cm\tests\

… collected 1 item cm/tests/test_phonebook.py::test_look_up_by_name PASSED [100%] ============================ 1 passed in 0.04s ==============================

Теперь добавим тест на поиск несуществующего элемента.

Так как теста теперь два - создание телефонной книги перенесём в фикстуру

Так как lookup() в Phonebook реализован как обычное обращение по ключу мы можем использовать эту особенность для обработки результатов.

import os import sys ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) sys.path.append(ROOT) import pytest from cm.phonebook import Phonebook @pytest.fixture def phonebook(): return Phonebook() def test_look_up_by_name(phonebook): phonebook.add("Yuri", "1961") result = phonebook.lookup("Yuri") assert result == "1961" def test_lookup_missing_name(phonebook): with pytest.raises(KeyError): phonebook.lookup("Niel")

python -m pytest -vv .\cm\tests\

… collected 2 items cm/tests/test_phonebook.py::test_look_up_by_name PASSED [ 50%] cm/tests/test_phonebook.py::test_lookup_missing_name PASSED [100%] =============================== 2 passed in 0.02s ===============================

В этом тесте мы ожидаем, что поднимется ислючение.

Поэтому, если разработчики решат заменить self.storage[name] на self.storage.get(name) тест начнёт выдавать False Positive.

def lookup(self, name): return self.storage.get(name)

python -m pytest -vv .\cm\tests\

… collected 2 items cm/tests/test_phonebook.py::test_look_up_by_name PASSED [ 50%] cm/tests/test_phonebook.py::test_lookup_missing_name FAILED [100%] ============================================= FAILURES ============================================= _____________________________________ test_lookup_missing_name _____________________________________ phonebook = <cm.phonebook.Phonebook object at 0x0000026BEE83C1D0> def test_lookup_missing_name(phonebook): > with pytest.raises(KeyError): ^^^^^^^^^^^^^^^^^^^^^^^ E Failed: DID NOT RAISE <class 'KeyError'> cm\tests\test_phonebook.py:22: Failed ===================================== short test summary info ====================================== FAILED cm/tests/test_phonebook.py::test_lookup_missing_name - Failed: DID NOT RAISE <class 'KeyError'> =================================== 1 failed, 1 passed in 0.07s ====================================

Тест придёстя заменить на

def test_lookup_missing_name(phonebook): assert phonebook.lookup("Niel") is None

Автор статьи: Андрей Олегович

Изображение баннера