当提供无效参数时,自动检测不抛出exceptin



试图模拟函数返回值,但使用Mock会导致在传递无效参数时不会引发异常:

In [1]: from unittest.mock import MagicMock, Mock, create_autospec
In [2]: def f(a):
...:   return 1
...: 
...: mf = Mock('f', autospec=True, return_value=2)
...: mf(None)
Out[2]: 2
In [3]: mf() # Why no error here?
Out[3]: 2

当使用create_autospec执行此操作时,它确实抛出了一个异常:

In [4]: mf2 = create_autospec(f)
In [5]: mf2(None)
Out[5]: <MagicMock name='mock()' id='140657928683232'>
In [6]: mf2()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-377889015999> in <module>
----> 1 mf2()
<string> in f(*args, **kwargs)
/usr/local/lib/python3.8/unittest/mock.py in checksig(*args, **kwargs)
177     func, sig = result
178     def checksig(*args, **kwargs):
--> 179         sig.bind(*args, **kwargs)
180     _copy_func_details(func, checksig)
181 
/usr/local/lib/python3.8/inspect.py in bind(self, *args, **kwargs)
3023         if the passed arguments can not be bound.
3024         """
-> 3025         return self._bind(args, kwargs)
3026 
3027     def bind_partial(self, /, *args, **kwargs):
/usr/local/lib/python3.8/inspect.py in _bind(self, args, kwargs, partial)
2938                             msg = 'missing a required argument: {arg!r}'
2939                             msg = msg.format(arg=param.name)
-> 2940                             raise TypeError(msg) from None
2941             else:
2942                 # We have a positional argument to process
TypeError: missing a required argument: 'a'
In [7]: 

首先,您希望创建通过spec=f而不是spec='f'Mock。否则,您将给出一个字符串作为规范,而不是函数f

其次,mock没有autospec参数。如果您阅读了文档的所有autospec部分,您会注意到autospec总是在使用patchpatch.object的上下文中提及。这两人的签名中都有autospec

这意味着mock创建中的autospec被接受为mock接受的剩余kwargs的一部分。这些用于在mock使用时在mock上配置其他属性。

因此,当您的mock只是使用一个普通的spec时,您可以确认它接受了一个本不应该存在的属性的读取:

from unittest.mock import Mock
def f(a,b):
return 1

mf = Mock(spec=f, autospec=True, return_value=2)
print(mf)
print(mf(None))
print(mf())
print(mf.autospec)

输出:

<Mock spec='function' id='139874223464352'>
2
2
True

所以,如果你像下面这样写代码,autospec就起作用了:

from unittest.mock import patch
def f(a):
return 1
with patch("__main__.f", autospec=True, return_value=2) as mf:
print(mf)
print(mf(None))
print(mf())

输出:

<function f at 0x7ff5a60a94c0>
2
Traceback (most recent call last):
... line 21, in <module>
print(mf())
...
TypeError: missing a required argument: 'a'

最新更新