据我所知Mock
,没有提供一种通过来实现想要的方法assert_called_with
。您可以访问call_args
和call_args_list
成员,并手动执行断言。
但是,这是一种实现您几乎想要的目标的简单(且肮脏的)方法。您必须实现一个其__eq__
方法始终返回的类True
:
def Any(cls):
class Any(cls):
def __eq__(self, other):
return True
return Any()
用作:
In [14]: caller = mock.Mock(return_value=None)
In [15]: caller(1,2,3, arg=True)
In [16]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=True)
In [17]: caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-17-c604faa06bd0> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(int), Any(int), arg=False)
/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
724 if self.call_args != (args, kwargs):
725 msg = self._format_mock_failure_message(args, kwargs)
--> 726 raise AssertionError(msg)
727
728
AssertionError: Expected call: mock(0, 0, 0, arg=False)
Actual call: mock(1, 2, 3, arg=True)
如您所见,它仅检查arg
。您必须创建的子类int
,否则比较将无法进行1。但是,您仍然必须提供所有参数。如果您有很多参数,则可以使用元组拆包来缩短代码:
In [18]: caller(1,2,3, arg=True)
In [19]: caller.assert_called_with(*[Any(int)]*3, arg=True)
除此之外,我想不出一种避免将所有参数传递给assert_called_with
您并按预期工作的方法。
上面的解决方案可以扩展为检查其他参数的类型。例如:
In [21]: def Any(cls):
...: class Any(cls):
...: def __eq__(self, other):
...: return isinstance(other, cls)
...: return Any()
In [22]: caller(1, 2.0, "string", {1:1}, [1,2,3])
In [23]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(list))
In [24]: caller(1, 2.0, "string", {1:1}, [1,2,3])
In [25]: caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-25-f607a20dd665> in <module>()
----> 1 caller.assert_called_with(Any(int), Any(float), Any(str), Any(dict), Any(tuple))
/usr/lib/python3.3/unittest/mock.py in assert_called_with(_mock_self, *args, **kwargs)
724 if self.call_args != (args, kwargs):
725 msg = self._format_mock_failure_message(args, kwargs)
--> 726 raise AssertionError(msg)
727
728
AssertionError: Expected call: mock(0, 0.0, '', {}, ())
Actual call: mock(1, 2.0, 'string', {1: 1}, [1, 2, 3])
但是,这不允许使用例如anint
或a作为参数str
。允许使用多个参数Any
并使用多重继承不会有帮助。我们可以使用解决abc.ABCMeta
def Any(*cls):
class Any(metaclass=abc.ABCMeta):
def __eq__(self, other):
return isinstance(other, cls)
for c in cls:
Any.register(c)
return Any()
例:
In [41]: caller(1, "ciao")
In [42]: caller.assert_called_with(Any(int, str), Any(int, str))
In [43]: caller("Hello, World!", 2)
In [44]: caller.assert_called_with(Any(int, str), Any(int, str))
1我使用了Any
函数的名称,因为它在代码中“用作类”。也是any
内置的...
requests-mock
模拟REST调用,则该模块可能也很有趣。