如何模拟 Python 构造函数的一部分以进行测试?

问题描述 投票:0回答:1

我是Python新手,所以如果这是一个重复或过于简单的问题,我深表歉意。我编写了一个协调器类,它调用另外两个使用 kafka-python 库从 Kafka 发送/读取数据的类。我想为我的协调员类编写一个单元测试,但我无法弄清楚如何最好地做到这一点。我希望我可以创建一个备用构造函数,可以将我的模拟对象传递到其中,但这似乎不起作用,因为我收到无法解析 test_mycoordinator 的错误。我是否会以错误的方式测试这个课程?我应该用Pythonic的方式来测试它吗?

这是我的测试类到目前为止的样子:

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 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
python unit-testing mocking python-mock
1个回答
53
投票

无需提供单独的构造函数。模拟修补您的代码以用模拟替换对象。只需在测试方法上使用

mock.patch()
装饰器即可;它将传递对生成的模拟对象的引用。

在创建实例之前

producer.Producer()
consumer.Consumer()都会被模拟出来:

from unittest 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
 类使用这些模拟对象而不是真正的代码。调用 
producer.Producer()
 返回一个新的模拟对象(与 
mock_producer.return_value
 引用的对象相同),等等

我假设

producer

consumer
 是顶级模块名称。如果不是,请提供完整的导入路径。来自 
mock.patch()
 文档:

target 应该是 'package.module.ClassName'

 形式的字符串。目标被导入,指定的对象被新对象替换,因此目标必须可以从您调用 
patch()
 的环境中导入。目标是在执行装饰函数时导入的,而不是在装饰时导入。

© www.soinside.com 2019 - 2024. All rights reserved.