← Назад к вопросам
Как вызывать принудительное исключение в негативных тестах?
2.0 Middle🔥 201 комментариев
#Python Core
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как вызывать принудительное исключение в негативных тестах?
В тестировании существует несколько подходов для проверки того, что ваш код корректно обрабатывает исключения. Рассмотрим самые эффективные методы.
1. Использование pytest.raises
Это основной и рекомендуемый способ в pytest:
import pytest
def divide(a, b):
if b == 0:
raise ZeroDivisionError("Деление на ноль")
return a / b
def test_divide_by_zero():
# Проверяем, что вызывается именно ZeroDivisionError
with pytest.raises(ZeroDivisionError):
divide(10, 0)
def test_divide_with_message():
# Проверяем сообщение об ошибке
with pytest.raises(ZeroDivisionError, match="Деление на ноль"):
divide(10, 0)
def test_divide_with_exception_info():
# Получаем объект исключения для дополнительной проверки
with pytest.raises(ZeroDivisionError) as exc_info:
divide(10, 0)
assert "ноль" in str(exc_info.value)
2. Проверка иерархии исключений
Если нужно проверить, что выбрасывается исключение из определённой иерархии:
class CustomError(Exception):
pass
class ValidationError(CustomError):
pass
def validate_email(email):
if "@" not in email:
raise ValidationError("Неверный формат email")
def test_validation():
# Работает для CustomError и его подклассов
with pytest.raises(CustomError):
validate_email("invalid_email")
# Проверка точного типа
with pytest.raises(ValidationError):
validate_email("invalid_email")
3. Использование mock для принудительного вызова исключений
Когда нужно заставить внешнюю функцию выбросить исключение:
from unittest.mock import Mock, patch
import pytest
def fetch_user(user_id):
"""Функция, которая зависит от внешнего API"""
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
def test_fetch_user_connection_error():
# Mock заставляет функцию выбросить исключение
with patch(requests.get) as mock_get:
mock_get.side_effect = ConnectionError("Нет соединения")
with pytest.raises(ConnectionError):
fetch_user(1)
4. Параметризованные тесты для проверки разных ошибок
import pytest
class Calculator:
def divide(self, a, b):
if not isinstance(a, (int, float)):
raise TypeError("a должно быть числом")
if not isinstance(b, (int, float)):
raise TypeError("b должно быть числом")
if b == 0:
raise ZeroDivisionError("Деление на ноль")
return a / b
@pytest.mark.parametrize("a,b,exc_type", [
(10, 0, ZeroDivisionError),
("abc", 5, TypeError),
(5, "xyz", TypeError),
])
def test_calculator_errors(a, b, exc_type):
calc = Calculator()
with pytest.raises(exc_type):
calc.divide(a, b)
5. Проверка множественных исключений
def test_multiple_exceptions():
# Проверяем, что один из типов исключений был выброшен
with pytest.raises((ValueError, TypeError)):
some_function()
6. Проверка контекста исключения
def process_data(data):
if not data:
raise ValueError("Данные пусты")
return len(data)
def test_with_context():
with pytest.raises(ValueError) as exc:
process_data([])
# Проверяем различные аспекты исключения
assert exc.typename == ValueError
assert "пусты" in str(exc.value)
assert exc.traceback # Traceback доступен
Лучшие практики
- Проверяй специфичные исключения — не ловите Exception
- Используй match для сообщений — проверяй содержание ошибки
- Не забывай про negative tests — это критически важно для надежности
- Параметризуй тесты — тестируй разные сценарии ошибок
- Используй mock для внешних зависимостей — не делай реальные запросы
Хорошее покрытие негативных тестов — это залог стабильного приложения в production.