[英]How can I autospec mock attributes that are None by default in python 3?
Consider this code: 考虑以下代码:
import unittest
from unittest.mock import patch
class Foo(object):
def __init__(self, bar=None):
self.bar = bar
def methodA(self):
print("In methodA")
def methodB(self):
print("In methodB")
def my_func(bar):
foo = Foo(bar)
if foo.bar:
foo.methodA()
foo.methodB()
class MyTestCase(unittest.TestCase):
def test_my_func(self):
bar = None
with patch("__main__.Foo", autospec=True) as foo:
my_func(bar)
foo.methodB.assert_called_once_with()
if __name__ == '__main__':
unittest.main()
The idea is fairly simple. 这个想法很简单。 I have a function whose behavior switches on the presence or absence of an instance attribute.
我有一个函数,该函数的行为会切换是否存在实例属性。 I'm trying to write a unit test that verifies only certain
Foo
methods are executed, depending on the attribute. 我正在尝试编写一个单元测试,以根据属性验证仅执行某些
Foo
方法。
Based on the mock library's patch and autospeccing docs, I thought setting autospec=True
in the patch()
context manager would suffice. 基于模拟库的补丁和自动指定文档,我认为在
patch()
上下文管理器中设置autospec=True
就足够了。 It doesn't. 没有。 The generated
Mock()
correctly includes mocks of methodA
and methodB
, but the test fails with this error: 所生成的
Mock()
正确地包括嘲笑methodA
和methodB
,但测试失败,此错误:
======================================================================
ERROR: test_my_func (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "so.py", line 28, in test_my_func
my_func(bar)
File "trash.py", line 18, in my_func
if foo.bar:
File "/.../python3.3/unittest/mock.py", line 549, in __getattr__
raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'bar'
I'm sure I'm missing something obvious, but I can't seem to figure out what. 我确定我缺少明显的东西,但似乎无法弄清楚。 How can I unittest
my_func()
? 如何对
my_func()
?
Part of my problem was a misunderstanding of patch's behavior. 我的部分问题是对补丁行为的误解。 The context manager I set up is returning an instance of the
__main__.Foo
mock, not the same instance used in my_func()
. 我设置的上下文管理器将返回
__main__.Foo
模拟的实例,而不是my_func()
使用的同一实例 。 To put it another way, even when I was able to mock Foo
properly, without autospec, I couldn't execute assert_called_once_with()
over any of its methods: It wasn't the same object. 换句话说,即使我能够在没有autospec的情况下正确模拟
Foo
,也无法assert_called_once_with()
任何方法执行assert_called_once_with()
:它不是同一对象。
One solution is to mock the method itself. 一种解决方案是模拟方法本身。 This works:
这有效:
def test_my_func(self):
bar = None
with patch('__main__.Foo.methodB') as mock_methodB:
my_func(bar)
mock_methodB.assert_called_once_with()
Another method would be modifying my_func()
to return foo: 另一种方法是修改
my_func()
以返回foo:
def my_func(bar):
foo = Foo(bar)
if foo.bar:
foo.methodA()
foo.methodB()
return foo
Because the function returns the mock under test, the following should work: 由于该函数返回了测试中的模拟,因此以下代码应该起作用:
def test_my_func(self):
bar = None
with patch('__main__.Foo', spec=True, bar=None):
foo = my_func(bar)
assert foo.methodB.called
assert not foo.methodA.called
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.