使用 python 的 mock patch.object 更改在另一个方法中调用的方法的返回值

是否可以模拟在我试图测试的另一个函数中调用的函数的返回值?我希望每次调用模拟方法(它将在我正在测试的许多方法中被调用)时都返回指定的变量。例如:

class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()

在单元测试中,我希望使用 mock 来更改 uses_some_other_method()的返回值,以便在 Foo中调用它时,它将返回在 @patch.object(...)中定义的值

299773 次浏览

可以这样做:

# foo.py
class Foo:
def method_1():
results = uses_some_other_method()




# testing.py
from mock import patch


@patch('Foo.uses_some_other_method', return_value="specific_value"):
def test_some_other_method(mock_some_other_method):
foo = Foo()
the_value = foo.method_1()
assert the_value == "specific_value"

这里有一个你可以阅读的资料来源: 修补错误的地方

有两种方法可以实现这一点: 使用 patch 和使用 patch.object

修补程序假定您不是直接导入对象,而是正由您正在测试的对象使用,如下所示

#foo.py
def some_fn():
return 'some_fn'


class Foo(object):
def method_1(self):
return some_fn()
#bar.py
import foo
class Bar(object):
def method_2(self):
tmp = foo.Foo()
return tmp.method_1()
#test_case_1.py
import bar
from mock import patch


@patch('foo.some_fn')
def test_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'

如果您直接导入要测试的模块,您可以使用 patch.object,如下所示:

#test_case_2.py
import foo
from mock import patch


@patch.object(foo, 'some_fn')
def test_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'

在这两种情况下,在测试函数完成之后 some _ fn 都将“ unmoked”。

编辑: 为了模拟多个函数,只需在函数中添加更多的修饰符,并添加参数以接受额外的参数

@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
...

注意,装饰符越接近函数定义,它在参数列表中的位置就越早。

让我解释一下您在说什么: 您希望在一个调用外部方法 uses_some_other_method的测试用例中测试 Foo。您希望模拟返回值,而不是调用实际的方法。

class Foo:
def method_1():
results = uses_some_other_method()
def method_n():
results = uses_some_other_method()

假设上面的代码在 foo.py中,而 uses_some_other_method在模块 bar.py中定义:

import unittest
import mock


from foo import Foo




class TestFoo(unittest.TestCase):


def setup(self):
self.foo = Foo()


@mock.patch('foo.uses_some_other_method')
def test_method_1(self, mock_method):
mock_method.return_value = 3
self.foo.method_1(*args, **kwargs)


mock_method.assert_called_with(*args, **kwargs)

如果希望每次传递不同参数时都更改返回值,则 mock提供 side_effect

为了补充 Silfheed 的回答,这是有用的,我需要修补问题对象的多个方法。我发现这样做更优雅:

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

要测试这个函数(或者类方法,没关系) ,可以通过使用 patch.object()sys.modules组合来修补类 SomeOtherClass的多个方法:

@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__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)

无论您需要修补多少个 SomeOtherClass方法,这都是可行的,并且具有独立的结果。

此外,使用相同的修补方法,如果需要,可以返回 SomeOtherClass的实际实例:

@patch.object(sys.modules['module.a_function.to_test'], 'SomeOtherClass')
def test__should_add_results(self, mocked_other_class):
other_class_instance = SomeOtherClass('some_controlled_parameters')
mocked_other_class.return_value = other_class_instance
...