I am attempting to write a unit test for a class's __init__
:
def __init__(self, buildNum, configFile = "configfile.txt"):
super(DevBuild, self).__init__(buildNum, configFile)
if configFile == "configfile.txt":
self.config.MakeDevBuild()
The config attribute is set by the super's __init__
. I'm using mock, and I want the config attribute to be a mock object. However, I haven't been able to figure out how to actually make that happen. Here's the best I could come up with for the test:
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()
However, this doesn't work--I get an error:
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'
Clearly I'm not setting the config attribute correctly, but I have no idea where exactly I should be setting it. Or for that matter, if what I want to do is even possible. Can anyone tell me what I need to do to make this work?
You can't mock __init__
by setting it directly - see _unsupported_magics in mock.py.
As for what you can do, you can mock __init__
by passing it to patch, like so:
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()
where SuperDevBuild
is a base class of DevBuild.
If you really want to mock super()
, you can perhaps make a class and then bind __init__
to object manually, like
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()
which works, but is quite ugly..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With