Вы можете определить assertNotRaises
, повторно используя около 90% первоначальной реализации assertRaises
в unittest
модуле. При таком подходе вы в конечном итоге получаете assertNotRaises
метод, который, помимо своего условия обратного сбоя, ведет себя идентично assertRaises
.
TLDR и живая демонстрация
Оказалось, что добавить assertNotRaises
метод к удивительно легко unittest.TestCase
(у меня ушло примерно в 4 раза больше времени, чтобы написать этот ответ, чем при написании кода). Вот живая демонстрация assertNotRaises
метода в действии . Точно так жеassertRaises
, вы можете либо передать вызываемый объект и аргументы assertNotRaises
, либо использовать его в with
выражении. Демонстрационная версия включает тестовые примеры, которые демонстрируют, что assertNotRaises
работает как задумано.
подробности
Реализация assertRaises
in unittest
довольно сложна, но с небольшим количеством умных подклассов вы можете переопределить и отменить условие сбоя.
assertRaises
это короткий метод, который в основном просто создает экземпляр unittest.case._AssertRaisesContext
класса и возвращает его (см. его определение в unittest.case
модуле). Вы можете определить свой собственный _AssertNotRaisesContext
класс, создав подкласс _AssertRaisesContext
и переопределив его __exit__
метод:
import traceback
from unittest.case import _AssertRaisesContext
class _AssertNotRaisesContext(_AssertRaisesContext):
def __exit__(self, exc_type, exc_value, tb):
if exc_type is not None:
self.exception = exc_value.with_traceback(None)
try:
exc_name = self.expected.__name__
except AttributeError:
exc_name = str(self.expected)
if self.obj_name:
self._raiseFailure("{} raised by {}".format(exc_name,
self.obj_name))
else:
self._raiseFailure("{} raised".format(exc_name))
else:
traceback.clear_frames(tb)
return True
Обычно вы определяете классы тестовых наборов, наследуя их от TestCase
. Если вы вместо этого наследуете от подкласса MyTestCase
:
class MyTestCase(unittest.TestCase):
def assertNotRaises(self, expected_exception, *args, **kwargs):
context = _AssertNotRaisesContext(expected_exception, self)
try:
return context.handle('assertNotRaises', args, kwargs)
finally:
context = None
у всех ваших тестовых случаев теперь есть assertNotRaises
метод, доступный для них.