Вы можете определить assertNotRaises, повторно используя около 90% первоначальной реализации assertRaisesв unittestмодуле. При таком подходе вы в конечном итоге получаете assertNotRaisesметод, который, помимо своего условия обратного сбоя, ведет себя идентично assertRaises.
TLDR и живая демонстрация
Оказалось, что добавить assertNotRaisesметод к удивительно легко unittest.TestCase(у меня ушло примерно в 4 раза больше времени, чтобы написать этот ответ, чем при написании кода). Вот живая демонстрация assertNotRaisesметода в действии . Точно так жеassertRaises , вы можете либо передать вызываемый объект и аргументы assertNotRaises, либо использовать его в withвыражении. Демонстрационная версия включает тестовые примеры, которые демонстрируют, что assertNotRaisesработает как задумано.
подробности
Реализация assertRaisesin 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метод, доступный для них.