有没有办法在模拟的方法/函数中访问原始函数,以便我可以修改参数并将其传递给原始函数?

时间:2015-05-19 21:53:53

标签: python mocking

我想修改传递给模块中方法的参数,而不是替换它的返回值。

我已经找到了解决这个问题的方法,但这似乎是有用的东西,并且变成了嘲弄的一课。

module.py

from third_party import ThirdPartyClass

ThirdPartyClass.do_something('foo', 'bar')
ThirdPartyClass.do_something('foo', 'baz')

tests.py

@mock.patch('module.ThirdPartyClass.do_something')
def test(do_something):
    # Instead of directly overriding its return value
    # I'd like to modify the arguments passed to this function.

    # change return value, no matter inputs
    do_something.return_value = 'foo'

    # change return value, based on inputs, but have no access to the original function
    do_something.side_effect = lambda x, y: y, x

    # how can I wrap do_something, so that I can modify its inputs and pass it back to the original function?
    # much like a decorator?

我尝试了类似下面的内容,但不仅重复而且难看,它不起作用。在进行了一些PDB内省之后..我想知道这是否仅仅是因为这个第三方库工作,因为我确实看到在side_effect内放置pdb时原始函数被成功调用。

无论是那个,还是一些自动嘲笑的魔法,我只是没有遵循我想要了解的内容。

def test():
    from third_party import ThirdPartyClass
    original_do_something = ThirdPartyClass.do_something

    with mock.patch('module.ThirdPartyClass.do_something' as mocked_do_something:
        def side_effect(arg1, arg2):
            return original_do_something(arg1, 'overridden')

        mocked_do_something.side_effect = side_effect

        # execute module.py

感谢任何指导!

2 个答案:

答案 0 :(得分:17)

您可能希望使用参数wraps进行模拟调用。 (Docs以供参考。)这样就可以调用原始函数,但它将包含Mock接口的所有内容。

因此,要更改调用原始函数的参数,您可能需要尝试这样:

#file org.py
def func(x):
    print(x)


#file main.py
from unittest import mock

import org


of = org.func
def wrapped(a):
    of('--{}--'.format(a))


with mock.patch('org.func', wraps=wrapped):
    org.func('x')
    org.func.assert_called_with('x')

结果:

 --x--

答案 1 :(得分:0)

诀窍是将仍要访问的原始基础函数作为参数传递给该函数。

例如,为了进行竞赛条件测试,让tempfile.mktemp返回一个现有路径名:

def mock_mktemp(*, orig_mktemp=tempfile.mktemp, **kwargs):
    """Ensure mktemp returns an existing pathname."""
    temp = orig_mktemp(**kwargs)
    open(temp, 'w').close()
    return temp

以上,orig_mktemp是在声明 时评估的,而不是在调用函数时评估的,因此所有调用都可以通过{{来访问tempfile.mktemp的原始方法1}}。

我按如下方式使用它:

orig_mktemp