Mocking a property call returning MagicMock, not value
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.
EliSquared
Updated on June 14, 2022Comments
-
EliSquared almost 2 years
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
-
EliSquared almost 7 yearsSo I tried to implement that (see my edit on my post), but I am still not getting the correct outputs.
-
EliSquared almost 7 yearsAcutally @mgilson I was able to get it to work I think I just changed the line in your code from
cfgB.Id = 17
tocfgB().Id = 17
. The parenthesis changed everything. Does that make sense to you? If you edit your post to include parenthesis I can mark it as the solution. -
EliSquared almost 7 yearsSo I couldn't get your suggestion to work, but I did find a solution with the help of @mgilson. See my final update.
-
mgilson almost 7 years@EliSquared -- Yeah, that makes sense. You want to attach the
Id
to thereturn_value
of your mock, not the mock itself (my bad). I've edited the code to reflect this.