Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
551 views
in Technique[技术] by (71.8m points)

python - How to mock a decorated function

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...