sed*_*nym 27 python unit-testing mocking
使用mock修补函数时,可以选择将autospec指定为True:
如果设置autospec = True,则使用要替换的对象的规范创建模拟.mock的所有属性也将具有要替换的对象的相应属性的规范.被模拟的方法和函数将检查其参数,如果使用错误的签名调用它们将引发TypeError.
(http://www.voidspace.org.uk/python/mock/patch.html)
我想知道为什么这不是默认行为?当然,我们几乎总是希望将错误的参数传递给我们修补的任何函数?
idj*_*jaw 25
唯一明确的解释方法是,实际引用文档说明使用自动查询的缺点以及使用它时为什么要小心:
然而,这并非没有警告和限制,这就是为什么它不是默认行为.为了知道spec对象上可用的属性,autospec必须内省(访问属性)规范.当您在模拟上遍历属性时,原始对象的相应遍历发生在引擎盖下.如果您的任何特定对象具有可以触发代码执行的属性或描述符,那么您可能无法使用自动规范.另一方面,设计对象要好得多,内省是安全的[4].
更严重的问题是,例如,在init方法中创建属性并且根本不存在于类中是常见的.autospec无法了解任何动态创建的属性,并将api限制为可见属性.
我认为这里的关键点是注意这一行:autospec无法知道任何动态创建的属性并将api限制为可见属性
因此,为了帮助更明确地说明自动指定中断的示例,从文档中获取的此示例显示了以下内容:
>>> class Something:
... def __init__(self):
... self.a = 33
...
>>> with patch('__main__.Something', autospec=True):
... thing = Something()
... thing.a
...
Traceback (most recent call last):
...
AttributeError: Mock object has no attribute 'a'
Run Code Online (Sandbox Code Playgroud)
如您所见,自动显示不知道a在创建Something对象时是否创建了属性.
通常情况下,对于我自己,我只是模拟补丁并且不要使用autospec,因为行为通常符合我的期望.
为实例属性赋值没有任何问题.
请注意以下功能示例:
import unittest
from mock import patch
def some_external_thing():
pass
def something(x):
return x
class MyRealClass:
def __init__(self):
self.a = some_external_thing()
def test_thing(self):
return something(self.a)
class MyTest(unittest.TestCase):
def setUp(self):
self.my_obj = MyRealClass()
@patch('__main__.some_external_thing')
@patch('__main__.something')
def test_my_things(self, mock_something, mock_some_external_thing):
mock_some_external_thing.return_value = "there be dragons"
self.my_obj.a = mock_some_external_thing.return_value
self.my_obj.test_thing()
mock_something.assert_called_once_with("there be dragons")
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
所以,我只是说我的测试用例,我想确保该some_external_thing()方法不会影响我的unittest的行为,所以我只是将我的实例属性分配给mock mock_some_external_thing.return_value = "there be dragons".
自动指定的操作本身可以执行代码,例如通过调用描述符。
>>> class A:
... @property
... def foo(self):
... print("rm -rf /")
...
>>> a = A()
>>> with mock.patch("__main__.a", autospec=False) as m:
... pass
...
>>> with mock.patch("__main__.a", autospec=True) as m:
... pass
...
rm -rf /
Run Code Online (Sandbox Code Playgroud)
因此,这是一个默认启用的有问题的功能,并且只能选择加入。
| 归档时间: |
|
| 查看次数: |
9599 次 |
| 最近记录: |