I have a system under test (Class Printer below), which uses another class (Class ContentContainer below). In one method (Method retrieve_and_show_content below), this class is instantiated. In the test for this method (Method test_printer_03 below), I want to instantiate a mock instead of the real class. However, it doesn't work like this.
I read here that I should change the object that a name points to with another one. It seems like the name of the object that I want to replace is simply ContentContainer, while the name of the object that I am actually replacing is TestMockClass.ContentContainer. Is this observation correct? If so, how do I change this? If I simply remove the prefix TestMockClass in the patch statement, I get a TypeError: Need a valid target to patch. You supplied: 'ContentContainer'.
#TestMockClass.py import unittest from mock import Mock, patch class Printer(): def __init__(self, name, cc): self.name = name self.cc = cc def show_content(self): text = '{0} says: {1}'.format(self.name, self.cc.content()) return text def retrieve_and_show_content(self): cc_tmp = ContentContainer() text = '{0} says: {1}'.format(self.name, cc_tmp.content()) return text class ContentContainer(): def __init__(self): self.method_counter() def content(self): return 'Content from ContentContainer' def method_counter(self): pass class Test(unittest.TestCase): '''No mocking''' def test_printer_01(self): cc = ContentContainer() sut = Printer('P01', cc) result = sut.show_content() expected_result = 'P01 says: Content from ContentContainer' self.assertEqual(result, expected_result, msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result)) result = sut.retrieve_and_show_content() expected_result = 'P01 says: Content from ContentContainer' self.assertEqual(result, expected_result, msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result)) '''Create a mock object, which is the input of the method under test''' def test_printer_02(self): mock_cc = Mock() mock_cc.content.return_value = 'Mocked content' sut = Printer('P02', mock_cc) result = sut.show_content() expected_result = 'P02 says: Mocked content' self.assertEqual(result, expected_result, msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result)) self.assertFalse(mock_cc.method_counter.called, 'Method method_counter shall not be called') '''Create a mock class, which is instantiated inside the method under test''' @patch('TestMockClass.ContentContainer') def test_printer_03(self, mock_cc): mock_cc.content.return_value = 'Mocked content' sut = Printer('P03', mock_cc) result = sut.retrieve_and_show_content() expected_result = 'P03 says: Mocked content' self.assertEqual(result, expected_result, msg = '\nRetrieved:\n{0} \nExpected:\n{1}'.format(result, expected_result)) self.assertFalse(mock_cc.method_counter.called, 'Method method_counter shall not be called') if __name__ == "__main__": unittest.main() When this unittest is run, the output is:
AssertionError: Retrieved: P03 says: Content from ContentContainer Expected: P03 says: Mocked content