Python 3 unittest patch doesn't return desired

2019-08-23 02:42发布

问题:

I am trying to use the unitttest mock framework (python 3.4.9) to mock one of the method in my test case. And it's failing as it doesn't return the mocked value.

This is the simplest example. In my case I can't change the way method being invoked.

mock method

def patch_this_method():
    return 100

Test Case

import unittest
from unittest.mock import patch
from libs.util import patch_this_method
import libs

class TestLibs(unittest.TestCase):
    @patch('libs.util.patch_this_method', return_value="200")
    def test_1(self, *mock):
        # return 200
        print(libs.util.patch_this_method())

        # this returns 100, original value
        print(patch_this_method())

回答1:

This line

from libs.util import patch_this_method

imports an object that is a copy of the original function, and the function has not been patched yet.

Then there is a strange * char before the mock parameter; it actually doesn't affect the code because it is not used and then you obtain the expected results. The first call links to the patched function. The other one doesn't.

Edit: About your question in the comment, you can't not with the patch decorator, using a simple name not contained in some package won't do. From the documentation of patch decorator (target is the string to patch):

target should be a string in the form 'package.module.ClassName'. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch() from. The target is imported when the decorated function is executed, not at decoration time.

But you can simply write:

from unittest.mock import Mock # or MagickMock if you need it
...
patch_this_method = Mock(return_value=200) 

And now your functions will use the mocked function.