使Mock.assert_called_with()对args和kwargs无关
单元测试的目的是测试功能,而不是关注具体的实现细节。Mock.assert_called_with()
是一个很方便的函数,但据我所知,它会把 *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)
有没有办法让这个比较更通用一些,这样在调用 func
时,具体使用了哪些 *args
作为 **kwargs
的细节就可以被忽略呢?
2 个回答
6
提交一个功能请求给mock。
根本问题是,如果没有真实的函数或类,mock就无法知道关键字参数的顺序。比如,调用 call(a=1, b=2)
和 call(b=2, a=1)
对mock来说是一样的,而调用 call(1, 2)
和 call(2, 1)
就不一样了。
如果你想让mock更通用,你需要传递一个调用原型或者一个函数来代替原型,比如:
amock.afunc.assert_called_with(1, 2, c=3, __prototype__=lambda a=None, b=None, c=None: None)
10
从Python 3.4开始,像你想要的那样,当创建一个可调用的Mock对象并指定了规范时,系统会自动检查特定的调用格式。而对于对象的方法,在使用自动规范时也是如此。
在Mock类的文档最后部分提到:
一个使用规范(spec)或规范集(spec_set)创建的可调用Mock对象,在匹配调用时会检查规范对象的参数格式。因此,它可以匹配实际调用的参数,无论这些参数是按位置传递的还是按名称传递的:
>>> 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()。在自动规范的情况下,它也适用于对Mock对象的方法调用。
在3.4版本中进行了更改:增加了对指定和自动指定的Mock对象的参数格式检查。