Python 模拟 call_args_list 解包元组以对参数进行断言
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39669538/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Python mock call_args_list unpacking tuples for assertion on arguments
提问by nackjicholson
I'm having some trouble dealing with the nested tuple which Mock.call_args_list
returns.
我在处理Mock.call_args_list
返回的嵌套元组时遇到了一些麻烦。
def test_foo(self):
def foo(fn):
fn('PASS and some other stuff')
f = Mock()
foo(f)
foo(f)
foo(f)
for call in f.call_args_list:
for args in call:
for arg in args:
self.assertTrue(arg.startswith('PASS'))
I would like to know if there is a better way to unpack that call_args_list on the mock object in order to make my assertion. This loop works, but it feels like there must be a more straight forward way.
我想知道是否有更好的方法来解压模拟对象上的 call_args_list 以便做出我的断言。这个循环有效,但感觉必须有更直接的方法。
回答by mgilson
I think that many of the difficulties here are wrapped up in the treatment of the "call" object. It can be thought of as a tuple with 2 members (args, kwargs)
and so it's frequently nice to unpack it:
我认为这里的许多困难都包含在“调用”对象的处理中。它可以被认为是一个有 2 个成员的元组,(args, kwargs)
所以解压它通常很好:
args, kwargs = call
Once it's unpacked, then you can make your assertions separately for args and kwargs (since one is a tuple and the other a dict)
解压后,您可以分别为 args 和 kwargs 进行断言(因为一个是元组,另一个是 dict)
def test_foo(self):
def foo(fn):
fn('PASS and some other stuff')
f = Mock()
foo(f)
foo(f)
foo(f)
for call in f.call_args_list:
args, kwargs = call
self.assertTrue(all(a.startswith('PASS') for a in args))
Note that sometimes the terseness isn't helpful (e.g. if there is an error):
请注意,有时简洁没有帮助(例如,如果出现错误):
for call in f.call_args_list:
args, kwargs = call
for a in args:
self.assertTrue(a.startswith('PASS'), msg="%s doesn't start with PASS" % a)
回答by wim
A nicer way might be to build up the expected calls your self then use a direct assertion:
更好的方法可能是建立自己的预期调用,然后使用直接断言:
>>> from mock import call, Mock
>>> f = Mock()
>>> f('first call')
<Mock name='mock()' id='31270416'>
>>> f('second call')
<Mock name='mock()' id='31270416'>
>>> expected_calls = [call(s + ' call') for s in ('first', 'second')]
>>> f.assert_has_calls(expected_calls)
Note that the calls must be sequential, if you don't want that then override the any_order
kwarg to the assertion.
请注意,调用必须是连续的,如果您不希望那样,则将any_order
kwarg覆盖到断言。
Also note that it's permitted for there to be extra calls before or after the specified calls. If you don't want that, you'll need to add another assertion:
另请注意,在指定的调用之前或之后允许有额外的调用。如果你不想这样,你需要添加另一个断言:
>>> assert f.call_count == len(expected_calls)
Addressing the comment of mgilson, here's an example of creating a dummy object that you can use for wildcard equality comparisons:
针对 mgilson 的评论,这里有一个创建可用于通配符相等比较的虚拟对象的示例:
>>> class AnySuffix(object):
... def __eq__(self, other):
... try:
... return other.startswith('PASS')
... except Exception:
... return False
...
>>> f = Mock()
>>> f('PASS and some other stuff')
<Mock name='mock()' id='28717456'>
>>> f('PASS more stuff')
<Mock name='mock()' id='28717456'>
>>> f("PASS blah blah don't care")
<Mock name='mock()' id='28717456'>
>>> expected_calls = [call(AnySuffix())]*3
>>> f.assert_has_calls(expected_calls)
And an example of the failure mode:
以及故障模式的示例:
>>> Mock().assert_has_calls(expected_calls)
AssertionError: Calls not found.
Expected: [call(<__main__.AnySuffix object at 0x1f6d750>),
call(<__main__.AnySuffix object at 0x1f6d750>),
call(<__main__.AnySuffix object at 0x1f6d750>)]
Actual: []