[英]Mocking a Python class that is instantiated in method under test
我有一个受测试的系统(下面的类Printer
),它使用另一个类(下面的Class ContentContainer
)。 在一个方法(下面的方法retrieve_and_show_content
)中,实例化此类。 在这个方法的测试中(下面的方法test_printer_03
),我想实例化一个mock而不是真正的类。 但是,它不会像这样工作。
我在这里读到我应该更改名称指向的对象与另一个。 看起来我要替换的对象的名称只是ContentContainer
,而我实际替换的对象的名称是TestMockClass.ContentContainer
。 这个观察是否正确? 如果是这样,我该如何更改? 如果我只是在patch语句中删除前缀TestMockClass
,我会得到一个TypeError: Need a valid target to patch. You supplied: 'ContentContainer'
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()
运行此单元测试时,输出为:
AssertionError:
Retrieved:
P03 says: Content from ContentContainer
Expected:
P03 says: Mocked content
两件事情:
因为ContentContainer
现在与测试位于同一个文件中,所以实际上需要修补__main__.ContentContainer
:
@patch('__main__.ContentContainer')
因为ContentContainer
是一个类,并且您在该类的实例上调用content
,所以您实际上希望模拟该实例上的content
,而不是类。 因此,您需要执行以下操作: mock_cc.return_value.content.return_value = 'Mocked content'
(请注意其中的附加.return_value
以确保您正在.return_value
实例,而不是类)。 这是因为调用类会创建一个实例。 因此,实例是类上调用的返回值。
因此测试应如下所示:
@patch('__main__.ContentContainer')
def test_printer_03(self, mock_cc):
mock_cc.return_value.content.return_value = 'Mocked content'
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.