Python模拟库:有没有办法从魔法模拟调用中获取相应的返回值?

时间:2013-08-02 23:31:23

标签: python unit-testing mocking python-mock

使用mock库编写Python测试时,我经常会得到“调用方法的参数”,像这样,

from __future__ import print_function
import mock

m = mock.MagicMock(side_effect=lambda x: x * x)
m(4)
print("m called with: ", m.call_args_list)

(这将打印m called with: [call(4)])。 问题:有没有办法获得返回值(在这种情况下,16)?

详细信息:在我的特定场景中,我想使用side_effect返回一个子模拟对象:内省该对象以查看对其进行调用的内容非常重要。例如,“真实代码”(非测试代码)可能会写,

myobj = m(4)
myobj.foo()

使用side_effect似乎是返回新的子模拟对象的便捷方式,但也保留call_args_list。但是,似乎MagicMock存储来自side_effect函数的返回值...我错了吗?

5 个答案:

答案 0 :(得分:1)

如果你问我,这不是嘲笑的目的。如果要断言返回值,则应直接调用该函数。如果你需要通过跳跃来记录函数返回的内容,那么你的设计很可能是有缺陷的。

例如,如果您有内部函数,则不应测试内部函数。如果您想测试内部功能,请将其公开访问。

所以不要这样:

def spam(input):
    def eggs(nested):
        return nested*2
    input = eggs(nested)
    return eggs(input)

这样做:

def eggs(nested):
    return nested*2

def spam(input):
    input = eggs(nested)
    return eggs(input)

答案 1 :(得分:0)

你不需要side_effect,这就是模仿已经没有它的东西,它们会返回其他模拟。

您可以通过mymock.return_value.assert_called_once_with(4)

对其进行断言

如果你这样做,你只需返回一个模拟,你有side_effect的其他地方的参考。

答案 2 :(得分:0)

使用return_value

例如,

import unittest

import mock

def foo(m):
    myobj = m(4)
    myobj.foo()

import unittest

class TestFoo(unittest.TestCase):
    def test_foo(self):
        m2 = mock.MagicMock()
        m = mock.MagicMock(return_value=m2)

        foo(m)

        m.assert_called_once_with(4)
        m2.foo.assert_called_once_with()

if __name__ == '__main__':
    unittest.main()

答案 3 :(得分:0)

您有一个call()对象。 您想在调用对象内部获取args。 也就是说,如果您获得

call_args_list[0] == call(3, 5)

您想要3和5。 可以为call()对象建立索引-首先要参考elem 0,这是实际参数的列表。然后,您希望将3放在它的内部作为第0个元素。

通过以下方式获取此信息:

cargs = call_args_list[0]
assert cargs[0][0] == 3

>>> mockObjThing.someFunc.call_args_list[0]
call('argOne', 'argTwo') 
>>> # DAGNABBIT I want argOne!!!
>>> cargs = mockObjThing.someFunc.call_args_list[0]
>>> cargs
call('argOne', 'argTwo') 
>>> cargs[0]
('argOne', 'argTwo')
>>> cargs[0][0]
'argOne'

答案 4 :(得分:0)

wraps 参数如何?

class MyClass:
    def foo(self, x):
        return(x * x)

然后您可以发出如下呼叫:

my_obj = MyClass()
with patch.object(MyClass, 'foo', wraps=MyClass().foo) as mocked_foo:
    my_result = my_obj.foo(4)
    mocked_foo.assert_called_with(4)    

和my_result将包含调用foo()的实际结果