简体   繁体   English

Python3 模拟用另一个函数替换函数

[英]Python3 mock replace function with another function

How do I mock a function with another function in python, that will also provide a mock object?如何使用 python 中的另一个函数来模拟一个函数,这也将提供一个模拟对象?

I have code that does something like:我有执行类似操作的代码:

def foo(arg1, arg2):
    r = bar(arg1)
    # does interesting things

I would like to substitute an implementation of the bar function, have it return sane values, and make sure it's called with the right arguments.我想替换bar函数的实现,让它返回合理的值,并确保使用正确的参数调用它。

I've tried this, where fake_bar is my simple replacement for bar :我试过这个,其中fake_bar是我对bar简单替代:

from unittest.mock import patch

def test_foo():
   with patch("x.bar", fake_bar) as mock_bar:
      actual = foo(arg1, arg2)
      assert actual == expected
      mock_bar.assert_called_once_with(arg1)

However, I get this error:但是,我收到此错误:

AttributeError: 'function' object has no attribute 'assert_called_once' AttributeError: 'function' 对象没有属性 'assert_called_once'

I found this question which suggests using create_autospec.我发现这个问题建议使用 create_autospec。 However, mock.create_autospec does not preserve return values.但是, mock.create_autospec 不保留返回值。

The python documentation suggests doing something like: python 文档建议执行以下操作:

mock_function = create_autospec(function, return_value='fishy')

However, my faked version of bar has computed return values that are not static and not so simple to put into an inline lambda.但是,我伪造的bar版本计算出的返回值不是静态的,也不是那么容易放入内联 lambda 中。

I feel like I'm missing something obvious.我觉得我错过了一些明显的东西。 Is there a way to easily both mock a function and replace its implementation with something more complex than a static return value?有没有一种方法可以轻松地模拟一个函数并用比静态返回值更复杂的东西替换它的实现?

Use the wraps keyword argument:使用wraps关键字参数:

def test_foo():
   with patch("x.bar", wraps=fake_bar) as mock_bar:
      actual = foo(arg1, arg2)
      assert actual == expected
      mock_bar.assert_called_once_with(arg1)

Here, x.bar is the fully qualified name of the function you are replacing, for example 'bigbusiness.account.AccountRepository.insert'.此处, x.bar是您要替换的函数的完全限定名称,例如“bigbusiness.account.AccountRepository.insert”。

mock_bar will still be a Mock (as is the default), but that Mock will wrap the function fake_bar , so the return value of mock_bar is the return value of fake_bar , rather than another Mock instance. mock_bar仍然将是一个Mock (这是默认值),但Mock将包装功能fake_bar ,这样的返回值mock_bar是的返回值fake_bar ,而不是另一种Mock实例。

AttributeError: 'function' object has no attribute 'assert_called_once AttributeError: 'function' 对象没有属性 'assert_Called_once

Sounds like you are trying to path with a regular function.听起来您正在尝试使用常规函数进行路径处理。 Patch with a MagicMock object whose return value is the result of calling fake_bar .使用返回值是调用fake_bar的结果的 MagicMock 对象修补。

from unittest.mock import patch, MagicMock

def foo(arg1, arg2):
    r = bar(arg1)
    # does interesting things

def bar(arg):
    return 2

def fake_bar():
    #calculate 2!
    return 2

def test_foo():
    with patch("__main__.bar", MagicMock(return_value=fake_bar())) as mock_bar:
        arg1,arg2 = 'a','b'
        foo(arg1, arg2)
        mock_bar.assert_called_once_with(arg1)
##        mock_bar.assert_called_once_with('w')
        print(mock_bar.call_args)

Variants:变体:

def test_foo():
    with patch("__main__.bar", autospec=True) as mock_bar:
        arg1,arg2 = 'a','b'
        mock_bar.return_value = fake_bar()
        foo(arg1, arg2)
        mock_bar.assert_called_once_with(arg1)
        print(mock_bar.call_args)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM