Использование assertRaises() с NoneType объектами в Python

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Чтобы проверить возникновение исключений при работе с объектом None, вызываемую функцию, генерирующую исключение, следует поместить внутрь блока assertRaises. Образец кода приведён ниже:

Python
Скопировать код
import unittest

class TestNoneOperation(unittest.TestCase):
    def test_none_method_call_raises(self):
        with self.assertRaises(AttributeError):
            none_var = None
            none_var.invalid_method()  # У None нет методов, подобно моим свободным воскресеньям ;)

unittest.main()

В данном примере мы убеждаемся, что при попытке вызвать несуществующий метод у объекта None возникает исключение AttributeError.

Кинга Идем в IT: пошаговый план для смены профессии

Корректный вызов assertRaises

Метод assertRaises() принимает аргументы по отдельности: тип исключения, вызываемую функцию и аргументы для этой функции. Если функция будет вызвана до передачи в assertRaises, тест перехватит исключение, не относящееся к тестируемым сценариям. Рассмотрим примеры:

Python
Скопировать код
# Это аналогично попытке бросить мяч в чужую корзину
self.assertRaises(ExceptionType, some_function(None))  # Неправильно! Попытка вызвать функцию приведёт к TypeError

# Мы точно знаем, куда бросаем мяч
self.assertRaises(ExceptionType, some_function, None)  # Правильно! Вызываемая функция и её аргументы передаются раздельно

Если исключение TypeError вызывается аргументами функции, используйте лямбда-выражение для отложенного вызова:

Python
Скопировать код
self.assertRaises(ExceptionType, lambda: some_function(None))  # Лямбда-функция отложит вызов аргумента

Проверка деталей исключения

Использование assertRaises() в качестве контекстного менеджера позволяет проверять тип и содержание исключения:

Python
Скопировать код
with self.assertRaises(SomeException) as cm:
    code_that_raises()  # Считаем, что здесь "ящик Пандоры" с ошибками

self.assertEqual('Ожидаемое сообщение', str(cm.exception))  # Проверяем, что это именно то исключение, которое мы ожидали

Этот подход оказывается особенно полезным для отлова ошибки "NoneType object is not subscriptable" (обычно случается при попытке обращения к объекту None, как к последовательности).

Стратегии для старых версий Python

  • Python 2.7 и выше: Используйте assertRaises() в качестве контекстного менеджера.
  • Python 2.6 и ниже: Используйте модуль unittest2, который расширяет возможности вашего тестового фреймворка, в том числе добавляет использование assertRaises() в качестве контекстного менеджера.

Продвинутые способы работы

В более сложных случаях, связанных с assertRaises(), может пригодиться функция operator.itemgetter, позволяющая избегать ошибки TypeError при имитировании индексирования объектов, которые не поддерживают индексацию:

Python
Скопировать код
import operator
self.assertRaises(TypeError, operator.itemgetter(0), None)  # Itemgetter играет роль охотника за None

Визуализация

Можно представить assertRaises() как сетку безопасности (🥅), предназначенную для отлова мяча (🏀) определённого типа:

Python
Скопировать код
with self.assertRaises(ExpectedException):
    throw_ball()  # Ожидаем, что сетка поймает баскетбольный мяч.

Когда в сценарий вступает NoneType, можно сказать, что мяч словно исчез в воздухе (💨):

Markdown
Скопировать код
with self.assertRaises(ExpectedException):
    throw_ball()  # Мяч не был брошен. Где же мяч?

В этой аналогии судья – это оператор утверждения, проверяющий, пойман ли именно тот мяч, который ожидался:

Markdown
Скопировать код
🥅 Сетка безопасности: "Я ловлю только 🏀!"
💨 Нет мяча: "Подождите, здесь и впрямь ничего нет!"
👨‍⚖️ Судья: "Ошибка! Ожидали 🏀, а поймали 💨."

Принцип: сетка безопасности (🥅) неэффективна, если в игре только воздух (💨); ей нужен конкретный мяч (🏀), то есть объект, генерирующий исключение.

Настройка вашего assertRaises

Контекст имеет значение

Применение assertRaises() как контекстного менеджера помогает поддерживать надежность тестов и обеспечивает их стабильное выполнение даже при обновлении версий Python, позволяя точно определить, что именно породило исключение.

Предупреждение ложноположительных результатов

Неправильная работа с assertRaises() может привести к ложноположительным результатам тестов. Убедитесь, что вызов исключения осуществлён намеренно, и он не связан с другими проблемами, не относящимися к тесту.

Использование слоёв совместимости для Python 2

Для версий Python 2.6 и более ранних модуль unittest2 предоставляет бесплатные обновления возможностей стандартного тестового пакета.

Полезные материалы

  1. unittest — Фреймворк модульного тестирования — Документация Python 3.12.2официальная документация Python по assertRaises.
  2. Начало работы с тестированием на Python – Real Python — подробные руководства по первым шагам в модульном тестировании на Python.
  3. Примеры использования unittest.assertRaises в Python — практические примеры использования unittest.assertRaises.
  4. Как правильно формулировать утверждения в тестах — документация pytest — глубокий анализ того, как сделать тестирование максимально эффективным и удобным для поддержки.
  5. Тестирование в Python 3: Введение в unittest – Mouse Vs Python — вводная статья по модульному тестированию для новичков.
  6. Встроенные константы — Документация Python 3.12.2 — информация о NoneType и его роли в Python.