For testing reasons, I need to be able to mock the inner/original function of a decorated one which is used somewhere else:
In mydecorator.py:
def my_decorator(f):
def wrapped_f():
print "decorated"
f()
return wrapped_f
@my_decorator
def function_to_be_mocked():
print 'original'
def function_to_be_mocked_undecorated():
print 'original'
def run_decorated():
function_to_be_mocked()
def run_undecorated():
decorated_funtion = my_decorator(function_to_be_mocked_undecorated)
decorated_funtion()
As you can see, I have several versions of the original function function_to_be_mocked, one with the decorator my_decorator and one 'naked'. The runner function run_decorated() calls the decorated version of function_to_be_mocked and run_undecorated() calls the undecorated version and applies the decorator 'manually'. The result of both are the same:
decorated
original
Now I want to test the runner function but I need to mock the original function function_to_be_mocked but also the mocked version should be decorated:
import unittest
import mydecorator
from mock import patch
def mock_function():
print 'mockified'
class Test(unittest.TestCase):
@patch('mydecorator.function_to_be_mocked_undecorated')
def test_undecorated_mocked(self, mock_function_to_be_mocked_undecorated):
mydecorator.function_to_be_mocked_undecorated = mock_function
mydecorator.run_undecorated()
assert 1==0
@patch('mydecorator.function_to_be_mocked')
def test_decoratorated_mocked(self, mock_function_to_be_mocked):
mydecorator.function_to_be_mocked = mock_function
mydecorator.run_decorated()
assert 1==0
This works as expected for the undecorated version test_undecorated_mocked:
decorated
mockified
But the decorated version gives:
mockified
so the decorator vanished.
Is it possible to get the decorated version working in the same way as the undecorated version, where the decorator is applied 'manually'?
I tried to expose the inner function in the decorator without success.
I saw this question How do you mock a function which has decorator apply to it in a unit test? but this doesn't help me.
By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it.
Python decorators can be easily tested by integration tests, but it is good practice to create some unit tests for them as well. You can easily unit test a decorator by applying it to a dummy function or mock.
Python applies the decorator when loading the module so setting function_to_be_mocked
to mock_function
in test_decoratorated_mocked
would indeed change that function into an undecorated function.
You'd need to manually add the decorator again if you wish to mock function_to_be_mocked
:
mydecorator.function_to_be_mocked = mydecorator.my_decorator(mock_function)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With