I have a decorator that accept two parameters callback
and onerror
, both should be callables something like this
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
I would like to test with I pass a invalid parameter, for example a non callable, it should raise a TypeError
Using Python unittest
what is the best approach to achieve this? I'm willing to do something like:
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')
It must be a better way, didn't?
As Leo K commented, there's a much easier way to test if some code raises an exception in a test, though different libraries spell things slightly differently. In a unittest.TestCase
, you can use self.assertRaises
as a context manager:
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
In fact, you could simplify things even more by doing away with unnecessary parts of the code being tested. Since you expect the mydecorator
class to raise the exception when it is called (rather than when the instance is called on the function), you can get rid of the dummy function and skip the @decorator
syntax all together. The assertRaises
method can even make the call for you:
def test_non_callable_callback_should_return_type_error(self):
self.assertraises(TypeError, mydecorator, 'this_is_not_a_callable')