Using Python's Mock Patch.object To Change The Return Value Of A Method Called Within Another Method
Solution 1:
There are two ways you can do this; with patch and with patch.object
Patch assumes that you are not directly importing the object but that it is being used by the object you are testing as in the following
#foo.pydefsome_fn():
return'some_fn'classFoo(object):defmethod_1(self):
return some_fn()
#bar.pyimport foo
classBar(object):
def method_2(self):
tmp = foo.Foo()
return tmp.method_1()
#test_case_1.pyimport bar
from mock import patch
@patch('foo.some_fn')deftest_bar(mock_some_fn):
mock_some_fn.return_value = 'test-val-1'
tmp = bar.Bar()
assert tmp.method_2() == 'test-val-1'
mock_some_fn.return_value = 'test-val-2'assert tmp.method_2() == 'test-val-2'
If you are directly importing the module to be tested, you can use patch.object as follows:
#test_case_2.pyimport foo
from mock import patch
@patch.object(foo, 'some_fn')deftest_foo(test_some_fn):
test_some_fn.return_value = 'test-val-1'
tmp = foo.Foo()
assert tmp.method_1() == 'test-val-1'
test_some_fn.return_value = 'test-val-2'assert tmp.method_1() == 'test-val-2'
In both cases some_fn will be 'un-mocked' after the test function is complete.
Edit: In order to mock multiple functions, just add more decorators to the function and add arguments to take in the extra parameters
@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
...
Note that the closer the decorator is to the function definition, the earlier it is in the parameter list.
Solution 2:
This can be done with something like this:
# foo.pyclassFoo:
defmethod_1():
results = uses_some_other_method()
# testing.pyfrom mock import patch
@patch('Foo.uses_some_other_method', return_value="specific_value"):deftest_some_other_method(mock_some_other_method):
foo = Foo()
the_value = foo.method_1()
assert the_value == "specific_value"
Here's a source that you can read: Patching in the wrong place
Solution 3:
Let me clarify what you're talking about: you want to test Foo
in a testcase, which calls external method uses_some_other_method
. Instead of calling the actual method, you want to mock the return value.
classFoo:
def method_1():
results =uses_some_other_method()
def method_n():
results =uses_some_other_method()
Suppose the above code is in foo.py
and uses_some_other_method
is defined in module bar.py
. Here is the unittest:
import unittest
import mock
from foo import Foo
classTestFoo(unittest.TestCase):
defsetup(self):
self.foo = Foo()
@mock.patch('foo.uses_some_other_method')deftest_method_1(self, mock_method):
mock_method.return_value = 3
self.foo.method_1(*args, **kwargs)
mock_method.assert_called_with(*args, **kwargs)
If you want to change the return value every time you passed in different arguments, mock
provides side_effect
.
Solution 4:
To add to Silfheed's answer, which was useful, I needed to patch multiple methods of the object in question. I found it more elegant to do it this way:
Given the following function to test, located in module.a_function.to_test.py
:
from some_other.module import SomeOtherClass
def add_results():
my_object = SomeOtherClass('some_contextual_parameters')
result_a = my_object.method_a()
result_b = my_object.method_b()
return result_a + result_b
To test this function (or class method, it doesn't matter), one can patch multiple methods of the class SomeOtherClass
by using patch.object()
in combination with sys.modules
:
@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')deftest__should_add_results(self, mocked_other_class):
mocked_other_class().method_a.return_value = 4
mocked_other_class().method_b.return_value = 7
self.assertEqual(add_results(), 11)
This works no matter the number of methods of SomeOtherClass
you need to patch, with independent results.
Also, using the same patching method, an actual instance of SomeOtherClass
can be returned if need be:
@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')deftest__should_add_results(self, mocked_other_class):
other_class_instance = SomeOtherClass('some_controlled_parameters')
mocked_other_class.return_value = other_class_instance
...
Post a Comment for "Using Python's Mock Patch.object To Change The Return Value Of A Method Called Within Another Method"