Короткий ответ
Нужно использовать контекстный менеджер pytest.raises(ИсключениеТип), внутри которого вызывается код, и pytest проверит, что исключение действительно возникло и имеет нужный тип.
Как это работает подробнее
pytest.raises перехватывает исключение внутри блока with; если исключение заданного типа не возникло вообще или возник другой тип, тест падает с ошибкой, явно сигнализируя, что ожидаемого поведения не произошло. Через атрибут .value можно получить сам объект исключения и проверить его сообщение или дополнительные атрибуты.
Пример кода
testing_example_297.py
import pytest
def withdraw(balance: float, amount: float) -> float:
if amount > balance:
raise ValueError("insufficient funds")
return balance - amount
def test_withdraw_raises_when_amount_exceeds_balance():
with pytest.raises(ValueError, match="insufficient funds"):
withdraw(balance=100, amount=150)Что использовать на практике
- Практика. Такой тест важен для проверки валидации входных данных и граничных условий — например, что деление на ноль или передача отрицательного возраста действительно приводит к понятной, явной ошибке, а не к тихому неверному результату или падению в неожиданном месте кода позже.
Подводные камни
- Риск. Проверять только факт исключения, но не его тип или сообщение, из-за чего тест пройдёт даже при неправильном, не относящемся к делу исключении (например, TypeError вместо ожидаемого ValueError). Оборачивать в pytest.raises слишком большой блок кода из нескольких вызовов, из-за чего непонятно, какая именно строка должна была бросить исключение, если тест упадёт.