使Mock.assert_called_with()对args和kwargs无关

18 投票
2 回答
9453 浏览
提问于 2025-04-17 12:22

单元测试的目的是测试功能,而不是关注具体的实现细节。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对象的参数格式检查。

撰写回答