У меня есть декоратор, который принимает два параметра callback и onerror, оба должны быть вызываемыми примерно так
class mydecorator(object):
def __init__(self, callback, onerror=None):
if callable(callback):
self.callback = callback
else:
raise TypeError('Callable expected in "callback" parameter')
self.onerror = onerror
if self.onerror and not callable(self.onerror):
raise TypeError('Callable expected in "onerror" parameter')
def __call__(self, func):
return self.__param__call__(func)
def __param__call__(self, func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
try:
self.callback()
except MyCustomException as e:
if self.onerror:
self.onerror(e.message, e.data)
else:
raise
return result
return wrapper
Я хотел бы протестировать, передав недопустимый параметр, например, не вызываемый, он должен вызвать TypeError
Как лучше всего добиться этого с помощью Python unittest? Я хочу сделать что-то вроде:
def test_non_callable_callback_should_return_type_error(self):
try:
@mydecorator('this_is_not_a_callable')
def my_phony_func():
pass
except TypeError:
# Correctly has raised a TypeError, lets just pass
pass
else:
# It has not raised an TypeError, let's fail
self.fail('TypeError not raised when a non callable passed to callback')
Это должен быть лучший способ, не так ли?






Как прокомментировал Лео К, существует гораздо более простой способ проверить, вызывает ли какой-то код исключение в тесте, хотя разные библиотеки описывают вещи немного по-разному. В unittest.TestCase вы можете использовать self.assertRaises в качестве диспетчера контекста:
def test_non_callable_callback_should_return_type_error(self):
with self.assertRaises(TypeError):
@mydecorator('this_is_not_a_callable')
def my_phony_func():
pass
Фактически, вы можете упростить задачу еще больше, отказавшись от ненужных частей тестируемого кода. Поскольку вы ожидаете, что класс mydecorator вызовет исключение при его вызове (а не при вызове экземпляра функции), вы можете избавиться от фиктивной функции и полностью пропустить синтаксис @decorator. Метод assertRaises может даже вызвать вам:
def test_non_callable_callback_should_return_type_error(self):
self.assertraises(TypeError, mydecorator, 'this_is_not_a_callable')
Что должен быть лучший способ сделать? Ваше использование класса с вызываемым экземпляром совершенно нормально, хотя и необычно (я более привык видеть, что обычные функции используются в качестве декораторов). Тест тоже в порядке. Если вы используете py.test, у него есть удобный
with pytest.raises(SystemExit): ...code..., который делает такие тесты немного более компактными.