使Mock.assert_called_with()与args vs kwargs无关

时间:2012-02-05 17:09:29

标签: python unit-testing mocking

单元测试应测试功能并尝试与实现细节无关。 Mock.assert_called_with()是一个方便的功能,但AFAIK会将*args*args**kwargs**kwargs进行比较。因此:

# class to be mocked during test
class SomeClass():
    def func(self,a,b,c=5):
        # ...

# code under test
somaclass_instance.func(1,b=2,c=3)

# test code that works
someclass_mock.func.assert_called_with(1,b=2,c=3)

# test code that won't work
someclass_mock.func.assert_called_with(1,2,c=3)
someclass_mock.func.assert_called_with(a=1,b=2,c=3)

有没有一种方法可以对此进行概括,以便在*args的调用**kwargs中使用func的具体内容(实际上是一个实现细节)将被忽略?

2 个答案:

答案 0 :(得分:5)

提交要模拟的功能请求。

基本问题是无法访问实际函数/类模拟无法知道关键字参数的顺序,即调用call(a=1, b=2)call(b=2, a=1)看起来与mock相同,而调用{{1 }和call(1, 2)没有。

如果你想推广mock,你需要传递一个调用原型或一个函数来代替原型,例如:

call(2, 1)

答案 1 :(得分:1)

从Python 3.4开始,就像你想要的那样,当使用spec创建可调用的Mock时,自动规范化特定的调用签名,并且在使用自动调整时使用对象方法。

the documentation of the Mock class的最后:

  

使用spec(或spec_set)创建的可调用模拟将会   在匹配调用时反省规范对象的签名   模拟。因此,它可以匹配实际调用的参数   无论他们是通过职位还是通​​过名字传递:

>>> def f(a, b, c): pass
...
>>> mock = Mock(spec=f)
>>> mock(1, 2, c=3)
<Mock name='mock()' id='140161580456576'>
>>> mock.assert_called_with(1, 2, 3)
>>> mock.assert_called_with(a=1, b=2, c=3)
     

这适用于assert_called_with(),assert_called_once_with(),   assert_has_calls()和assert_any_call()。自动指定时,它会   也适用于模拟对象的方法调用。

     

在3.4版中更改:在已推测和自动指定的模拟对象上添加了签名内省。