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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18191275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 10:08:31  来源:igfitidea点击:

Using python's mock patch.object to change the return value of a method called within another method

pythonunit-testingmockingpatch

提问by mdoc-2011

Is it possible to mock a return value of a function called within another function I am trying to test? I would like the mocked method (which will be called in many methods I'm testing) to returned my specified variables each time it is called. For example:

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

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

In the unit test, I would like to use mock to change the return value of uses_some_other_method()so that any time it is called in Foo, it will return what I defined in @patch.object(...)

在单元测试中,我想使用模拟来更改的返回值,uses_some_other_method()以便任何时候调用Foo它,它都会返回我在@patch.object(...)

采纳答案by Silfheed

There are two ways you can do this; with patch and with patch.object

有两种方法可以做到这一点;带补丁和带 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

Patch 假定您不是直接导入对象,而是您正在测试的对象正在使用它,如下所示

#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'

If you are directly importing the module to be tested, you can use patch.object as follows:

如果是直接导入待测模块,可以使用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'

In both cases some_fn will be 'un-mocked' after the test function is complete.

在这两种情况下,在测试功能完成后 some_fn 将被“取消模拟”。

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.

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

回答by chipz

This can be done with something like this:

这可以通过这样的事情来完成:

# 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"

Here's a source that you can read: Patching in the wrong place

这是您可以阅读的来源:在错误的地方打补丁

回答by cizixs

Let me clarify what you're talking about: you want to test Fooin a testcase, which calls external method uses_some_other_method. Instead of calling the actual method, you want to mock the return value.

让我澄清一下您在说什么:您想Foo在调用外部方法的测试用例中进行测试uses_some_other_method。您想要模拟返回值,而不是调用实际方法。

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

Suppose the above code is in foo.pyand uses_some_other_methodis defined in module bar.py. Here is the unittest:

假设上面的代码在foo.py并且uses_some_other_method在 module 中定义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)

If you want to change the return value every time you passed in different arguments, mockprovides side_effect.

如果您想在每次传入不同参数时更改返回值,请mock提供side_effect.