I have the following configuration class:
class ConfigB(object):
Id = None
def __Init__(self, Id):
self.Id = Id
Which is instantiated in the following class and the property printed:
from config.ConfigB import ConfigB
class FileRunner(object):
def runProcess(self, Id)
cfgB = ConfigB(Id)
print(cfgB.Id)
I have created the following test class to test it, where I am trying to mock both the instantiation and the cfgB.Id property call:
import unittest
import unittest.mock imort MagicMock
import mock
from FileRunner import FileRunner
class TestFileRunner(unittest.TestCase):
@mock.patch('ConfigB.ConfigB.__init__')
@mock.patch('ConfigB.ConfigB.Id')
def test_methodscalled(self, cfgBId, cfgBInit):
fileRunner = FileRunner()
cfgBId.return_value = 17
cfgBInit.return_value = None
print(cfgBId)
fileRunner.runProcess(1)
Note the print(cfgBId) statement before fileRunner is called. I get the following output:
<MagicMock name='Id' id='157297352'>
<MagicMock name='Id' id='157297352'>
For some reason when I set the return value here in the test class:
cfgBId.return_value = 17
That is not getting called on the line in the FileRunner() class:
print(cfgB.Id)
What do I need to do to properly get my configuration property to display?
Also note that my 'ConfigB' class instantiation is much more complicated than displayed above which is why I want to patch the instantiation and the call to the Id property.
*Update: I have changed my class as suggested by @mgilson but it is still not working:
import unittest
import unittest.mock imort MagicMock
import mock
from FileRunner import FileRunner
class TestFileRunner(unittest.TestCase):
@mock.patch('FileRunner.ConfigB')
def test_methodscalled(self, cfgB):
fileRunner = FileRunner()
cfgB.Id = 17
print(cfgBId)
fileRunner.runProcess(1)
I am now getting the following output from the two print statements:
<MagicMock name='ConfigB' id='157793640'>
<MagicMock name='ConfigB().Id' id='157020512'>
Any ideas why the above isn't working?
*Solution:
I was able to get it to work after a minor change to the test method that @mgilson suggested:
import unittest
from unittest.mock import MagicMock
import mock
from FileRunner import FileRunner
class TestFileRunner(unittest.TestCase):
@mock.patch('FileRunner.ConfigB')
def test_methodscalled(self, configB):
fileRunner = FileRunner()
cfgB = MagicMock()
cfgB.Id = 17
#This will return the cfgB MagicMock when `ConfigB(Id)` is called in `FileRunner` class
configB.return_value = cfgB
print(cfgB.Id)
fileRunner.runProcess(1)
#To test whether `ConfigB(17)` was called
configB.assert_called_with(17)
I now get the following outputs:
<MagicMock name='ConfigB' id='157147936'>
17
It looks to me like it would be better to just replace the entire ConfigB object in the FileRunner
namespace. Then your test looks something like this:
import unittest
import unittest.mock imort MagicMock
import mock
from FileRunner import FileRunner
class TestFileRunner(unittest.TestCase):
@mock.patch('FileRunner.ConfigB')
def test_methodscalled(self, cfgB):
fileRunner = FileRunner()
cfgB.return_value.Id = 17
fileRunner.runProcess(1)
Note that @mock.patch('FileRunner.ConfigB')
is going to replace the ConfigB
class in the FileRunner
namespace with a mock. You can then configure the mock to do whatever you like -- e.g. have an Id
that equals 17.
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