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

mdo*_*011 55 python unit-testing patch mocking

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

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()
Run Code Online (Sandbox Code Playgroud)

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

Sil*_*eed 82

有两种方法可以做到这一点; 与补丁和patch.object

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

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

class Foo(object):
    def method_1(self):
        return some_fn()
Run Code Online (Sandbox Code Playgroud)

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

#bar.py
import foo
class Bar(object):
    def method_2(self):
        tmp = foo.Foo()
        return tmp.method_1()
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,在测试功能完成后,some_fn将被"未模拟".

编辑:为了模拟多个函数,只需向函数添加更多装饰器并添加参数以获取额外参数

#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'
Run Code Online (Sandbox Code Playgroud)

请注意,装饰器离函数定义越近,它在参数列表中越早.

  • 非常感谢你这句话:"装饰者越接近函数定义,它就越早在参数列表中." 花了1个小时调试这个...... (6认同)
  • 感谢您对patch和patch.object之间的区别的解释。 (2认同)
  • 如果foo是我无权访问的库,而我想模拟的是对method_1的调用该怎么办? (2认同)

chi*_*ipz 14

这可以通过以下方式完成:

# 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"
Run Code Online (Sandbox Code Playgroud)

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


ciz*_*ixs 6

让我澄清一下你在谈论的内容:你想Foo在一个调用外部方法的测试用例中进行测试uses_some_other_method.您想要模拟返回值,而不是调用实际方法.

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()
Run Code Online (Sandbox Code Playgroud)

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

import unitest
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)
Run Code Online (Sandbox Code Playgroud)

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