我如何模拟 python 构造函数的一部分来进行测试?
How do I mock part of a python constructor just for testing?
我是 Python 的新手,如果这是一个重复或过于简单的问题,我深表歉意。我写了一个协调器 class,它调用另外两个使用 kafka-python 库的 classes 到来自 Kafka 的 send/read 数据。我想为我的协调员 class 编写单元测试,但我无法弄清楚如何最好地解决这个问题。我希望我可以制作一个备用构造函数,我可以将我的模拟对象传递给它,但这似乎不起作用,因为我收到 test_mycoordinator 无法解决的错误。我要以错误的方式测试这个 class 吗?是否有 pythonic 方法我应该测试它?
目前我的测试 class 是这样的:
import unittest
from mock import Mock
from mypackage import mycoordinator
class MyTest(unittest.TestCase):
def setUpModule(self):
# Create a mock producer
producer_attributes = ['__init__', 'run', 'stop']
mock_producer = Mock(name='Producer', spec=producer_attributes)
# Create a mock consumer
consumer_attributes = ['__init__', 'run', 'stop']
data_out = [{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
mock_consumer = Mock(
name='Consumer', spec=consumer_attributes, return_value=data_out)
self.coor = mycoordinator.test_mycoordinator(mock_producer, mock_consumer)
def test_send_data(self):
# Create some data and send it to the producer
count = 0
while count < 3:
count += 1
testName = 'test' + str(count)
self.coor.sendData(testName , None)
这是我要测试的class:
class MyCoordinator():
def __init__(self):
# Process Command Line Arguments using argparse
...
# Initialize the producer and the consumer
self.myproducer = producer.Producer(self.servers,
self.producer_topic_name)
self.myconsumer = consumer.Consumer(self.servers,
self.consumer_topic_name)
# Constructor used for testing -- DOES NOT WORK
@classmethod
def test_mycoordinator(cls, mock_producer, mock_consumer):
cls.myproducer = mock_producer
cls.myconsumer = mock_consumer
# Send the data to the producer
def sendData(self, data, key):
self.myproducer.run(data, key)
# Receive data from the consumer
def getData(self):
data = self.myconsumer.run()
return data
无需提供单独的构造函数。模拟 修补您的代码 以用模拟替换对象。只需在您的测试方法上使用 mock.patch()
decorator;它将传递对生成的模拟对象的引用。
然后 producer.Producer()
和 consumer.Consumer()
都被模拟出来 在您创建实例之前 :
import mock
class MyTest(unittest.TestCase):
@mock.patch('producer.Producer', autospec=True)
@mock.patch('consumer.Consumer', autospec=True)
def test_send_data(self, mock_consumer, mock_producer):
# configure the consumer instance run method
consumer_instance = mock_consumer.return_value
consumer_instance.run.return_value = [
{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
coor = MyCoordinator()
# Create some data and send it to the producer
for count in range(3):
coor.sendData('test{}'.format(count) , None)
# Now verify that the mocks have been called correctly
mock_producer.assert_has_calls([
mock.Call('test1', None),
mock.Call('test2', None),
mock.Call('test3', None)])
所以在调用 test_send_data
的那一刻,mock.patch()
代码用模拟对象替换了 producer.Producer
引用。您的 MyCoordinator
class 然后使用这些模拟对象而不是真实代码。调用 producer.Producer()
returns 一个新的模拟对象(mock_producer.return_value
引用的同一对象),等等
我假设 producer
和 consumer
是顶级模块名称。如果不是,请提供完整的导入路径。来自 mock.patch()
文档:
target should be a string in the form 'package.module.ClassName'
. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are calling patch()
from. The target is imported when the decorated function is executed, not at decoration time.
我是 Python 的新手,如果这是一个重复或过于简单的问题,我深表歉意。我写了一个协调器 class,它调用另外两个使用 kafka-python 库的 classes 到来自 Kafka 的 send/read 数据。我想为我的协调员 class 编写单元测试,但我无法弄清楚如何最好地解决这个问题。我希望我可以制作一个备用构造函数,我可以将我的模拟对象传递给它,但这似乎不起作用,因为我收到 test_mycoordinator 无法解决的错误。我要以错误的方式测试这个 class 吗?是否有 pythonic 方法我应该测试它?
目前我的测试 class 是这样的:
import unittest
from mock import Mock
from mypackage import mycoordinator
class MyTest(unittest.TestCase):
def setUpModule(self):
# Create a mock producer
producer_attributes = ['__init__', 'run', 'stop']
mock_producer = Mock(name='Producer', spec=producer_attributes)
# Create a mock consumer
consumer_attributes = ['__init__', 'run', 'stop']
data_out = [{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
mock_consumer = Mock(
name='Consumer', spec=consumer_attributes, return_value=data_out)
self.coor = mycoordinator.test_mycoordinator(mock_producer, mock_consumer)
def test_send_data(self):
# Create some data and send it to the producer
count = 0
while count < 3:
count += 1
testName = 'test' + str(count)
self.coor.sendData(testName , None)
这是我要测试的class:
class MyCoordinator():
def __init__(self):
# Process Command Line Arguments using argparse
...
# Initialize the producer and the consumer
self.myproducer = producer.Producer(self.servers,
self.producer_topic_name)
self.myconsumer = consumer.Consumer(self.servers,
self.consumer_topic_name)
# Constructor used for testing -- DOES NOT WORK
@classmethod
def test_mycoordinator(cls, mock_producer, mock_consumer):
cls.myproducer = mock_producer
cls.myconsumer = mock_consumer
# Send the data to the producer
def sendData(self, data, key):
self.myproducer.run(data, key)
# Receive data from the consumer
def getData(self):
data = self.myconsumer.run()
return data
无需提供单独的构造函数。模拟 修补您的代码 以用模拟替换对象。只需在您的测试方法上使用 mock.patch()
decorator;它将传递对生成的模拟对象的引用。
然后 producer.Producer()
和 consumer.Consumer()
都被模拟出来 在您创建实例之前 :
import mock
class MyTest(unittest.TestCase):
@mock.patch('producer.Producer', autospec=True)
@mock.patch('consumer.Consumer', autospec=True)
def test_send_data(self, mock_consumer, mock_producer):
# configure the consumer instance run method
consumer_instance = mock_consumer.return_value
consumer_instance.run.return_value = [
{u'dataObjectID': u'test1'},
{u'dataObjectID': u'test2'},
{u'dataObjectID': u'test3'}]
coor = MyCoordinator()
# Create some data and send it to the producer
for count in range(3):
coor.sendData('test{}'.format(count) , None)
# Now verify that the mocks have been called correctly
mock_producer.assert_has_calls([
mock.Call('test1', None),
mock.Call('test2', None),
mock.Call('test3', None)])
所以在调用 test_send_data
的那一刻,mock.patch()
代码用模拟对象替换了 producer.Producer
引用。您的 MyCoordinator
class 然后使用这些模拟对象而不是真实代码。调用 producer.Producer()
returns 一个新的模拟对象(mock_producer.return_value
引用的同一对象),等等
我假设 producer
和 consumer
是顶级模块名称。如果不是,请提供完整的导入路径。来自 mock.patch()
文档:
target should be a string in the form
'package.module.ClassName'
. The target is imported and the specified object replaced with the new object, so the target must be importable from the environment you are callingpatch()
from. The target is imported when the decorated function is executed, not at decoration time.