5

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

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()

Usingside_effect似乎是一种返回新子模拟对象的便捷方式,但也可以保留call_args_list. 但是,商店似乎没有MagicMockside_effect函数返回值……我错了吗?

4

5 回答 5

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)
于 2014-02-11T19:15:35.883 回答
1

那么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() 的实际结果

于 2020-09-10T14:03:16.780 回答
0

Use return_value.

For example,

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()
于 2013-08-03T04:49:44.027 回答
0

你不需要 a side_effect,这就是没有它的模拟已经做了,他们返回其他模拟。

你通过做对他们做出断言mymock.return_value.assert_called_once_with(4)

如果你这样做了,你只会返回一个你在其他地方引用过的模拟side_effect

于 2013-08-02T23:40:21.377 回答
0

你有一个 call() 对象。您想在调用对象中获取参数。也就是说,如果你得到

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'
于 2018-09-17T14:36:14.123 回答