如何模拟超类的__init__为单元测试创建一个包含模拟对象的属性?
问题描述:
我试图写一个单元测试一类的__init__
:如何模拟超类的__init__为单元测试创建一个包含模拟对象的属性?
def __init__(self, buildNum, configFile = "configfile.txt"):
super(DevBuild, self).__init__(buildNum, configFile)
if configFile == "configfile.txt":
self.config.MakeDevBuild()
的配置属性由超级的__init__
设置。我使用的是mock,我希望config属性是一个模拟对象。但是,我一直无法弄清楚如何真正做到这一点。这是我能想出的测试最佳:
def test_init(self):
with patch('DevBuild.super', create=True) as mock_super:
mock_MakeDevBuild = MagicMock()
mock_super.return_value.config.MakeDevBuild = mock_MakeDevBuild
# Test with manual configuration
self.testBuild = DevBuild("42", "devconfigfile.txt")
self.assertFalse(mock_MakeDevBuild.called)
# Test with automated configuration
self.testBuild = DevBuild("42")
mock_MakeDevBuild.assert_called_once_with()
但是,这并不工作 - 我得到一个错误:
Error
Traceback (most recent call last):
File "/Users/khagler/Projects/BuildClass/BuildClass/test_devBuild.py", line 17, in test_init
self.testBuild = DevBuild("42")
File "/Users/khagler/Projects/BuildClass/BuildClass/DevBuild.py", line 39, in __init__
self.config.MakeDevBuild()
AttributeError: 'DevBuild' object has no attribute 'config'
显然我没有设置正确的配置属性,但我不知道其中正是我应该设置它。或者就此而言,如果我想要做什么甚至是可能的。任何人都可以告诉我我需要做些什么来完成这项工作?
答
你不能直接设置它嘲笑__init__
- 见_unsupported_magics in mock.py。
至于你能做什么,你可以通过它来修补,像这样嘲笑__init__
:
mock_makeDevBuild = MagicMock()
def mock_init(self, buildNum, configFile):
self.config = MagicMock()
self.config.MakeDevBuild = mock_makeDevBuild
with patch('DevBuild.SuperDevBuild.__init__', new=mock_init):
DevBuild("42")
mock_makeDevBuild.assert_called_once_with()
其中SuperDevBuild
是一个基类DevBuild的。
如果你真的想嘲笑super()
,可以或许使一个类,然后绑定__init__
手动对象,像
mock_makeDevBuild = MagicMock()
def get_mock_super(tp, obj):
class mock_super(object):
@staticmethod
def __init__(buildNum, configFile):
obj.config = MagicMock()
obj.config.MakeDevBuild = mock_makeDevBuild
return mock_super
with patch('DevBuild.super', create=True, new=get_mock_super):
DevBuild("42")
mock_makeDevBuild.assert_called_once_with()
其作品,但也相当难看..
+1
谢谢,第一种方法做了我所需要的。 – khagler
的观察: 'super'的返回值不是具有'config'属性的对象,而是具有'__init__'方法的对象,该方法将向其参数添加一个'config'属性。 – chepner
是整个'__init__'吗?如果是,那么只有在你的测试中没有传递配置文件名时才会添加self.config.MakeDevBuild。 – jlujan