Как сгенерировать исключение в Python

Ответ

Для принудительной генерации (вызова) исключения в Python используется оператор raise. Он немедленно прерывает нормальное выполнение кода и передает управление ближайшему обработчику except.

Это ключевой механизм для сигнализации об ошибках или нештатных ситуациях в коде.

Синтаксис: raise ExceptionType("Сообщение об ошибке")

Пример использования в функции:

def get_user_by_id(user_id: int):
    if not isinstance(user_id, int) or user_id <= 0:
        # Генерируем исключение, если ID некорректен
        raise ValueError("ID пользователя должен быть положительным целым числом")
    # ... логика поиска пользователя в базе данных
    return {"id": user_id, "name": "John Doe"}

Применение в негативном тестировании

В тестах raise используется для проверки того, что код корректно обрабатывает ошибочные входные данные. Лучшей практикой является использование контекстного менеджера pytest.raises.

Пример теста с pytest:

import pytest

def test_get_user_with_invalid_id():
    # Проверяем, что вызов функции с user_id = -1
    # действительно генерирует исключение ValueError
    with pytest.raises(ValueError, match="ID пользователя должен быть"):
        get_user_by_id(-1)

Этот тест успешно пройдет, только если внутри блока with будет сгенерировано исключение ValueError, текст которого соответствует регулярному выражению в match.

Ответ 18+ 🔞

Да ты посмотри, что за хуйня творится в коде иногда! Ну вот представь: летит твоя программа, как шаровая молния, и тут — бац! — на тебе, какая-то неожиданная ситуация, которую в лоб не предусмотрел. Что делать? Правильно, орать на весь мир, что всё пошло по пизде! Для этого в Python и есть оператор raise. Он как красная кнопка — жмёшь, и нормальная работа кода немедленно накрывается медным тазом, а управление летит прямиком к ближайшему паникёру, то есть обработчику except.

Как это выглядит, спросишь? raise ExceptionType("Сообщение об ошибке")

Вот тебе живой пример, чтоб понятнее было:

def get_user_by_id(user_id: int):
    if not isinstance(user_id, int) or user_id <= 0:
        # А вот тут мы и взываем к богам, если ID — полная хуйня
        raise ValueError("ID пользователя должен быть положительным целым числом")
    # ... дальше идёт какая-то магия с базой данных
    return {"id": user_id, "name": "John Doe"}

А зачем это в тестах, спросит пытливый ум?

А вот зачем, ёпта! Чтобы проверить, не сломается ли твой код, если в него сунуть какую-нибудь дичь. Это называется негативным тестированием. И лучший способ это сделать — использовать pytest.raises. Это как подсунуть коту сардельку и ждать, что он на неё среагирует.

Смотри, как это круто выглядит в тесте:

import pytest

def test_get_user_with_invalid_id():
    # Сейчас мы специально вызовем функцию с откровенным говном (user_id = -1)
    # и будем ждать, что она правильно взбесится и выкинет ValueError
    with pytest.raises(ValueError, match="ID пользователя должен быть"):
        get_user_by_id(-1)

И этот тест пройдёт на ура только в одном случае: если внутри этого блока with функция действительно взорвётся нужным исключением ValueError, да ещё и с текстом, который мы ожидаем. А если не взорвётся — ну, значит, код говнарый, не умеет ругаться на кривые данные. Вот и вся философия, в рот меня чих-пых!