我如何模拟 python 构造函数的一部分只是为了测试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43354242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I mock part of a python constructor just for testing?
提问by jencoston
I am new to Python, so I apologize if this is a duplicate or overly simple question. I have written a coordinator class that calls two other classes that use the kafka-python library to send/read data from Kafka. I want to write a unit test for my coordinator class but I'm having trouble figuring out how to best to go about this. I was hoping that I could make an alternate constructor that I could pass my mocked objects into, but this doesn't seem to be working as I get an error that test_mycoordinator cannot be resolved. Am I going about testing this class the wrong way? Is there a pythonic way I should be testing it?
我是 Python 新手,所以如果这是一个重复或过于简单的问题,我深表歉意。我编写了一个协调器类,它调用另外两个使用 kafka-python 库从 Kafka 发送/读取数据的类。我想为我的协调器类编写一个单元测试,但我无法弄清楚如何最好地解决这个问题。我希望我可以创建一个替代构造函数,我可以将我的模拟对象传递给它,但这似乎不起作用,因为我收到了 test_mycoordinator 无法解决的错误。我会以错误的方式测试这个类吗?我应该测试它的pythonic方式吗?
Here is what my test class looks like so far:
这是我的测试类到目前为止的样子:
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)
And here is the class I am trying to test:
这是我要测试的课程:
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
回答by Martijn Pieters
There is no need to provide a separate constructor. Mocking patches your codeto replace objects with mocks. Just use the mock.patch()
decoratoron your test methods; it'll pass in references to the generated mock objects.
无需提供单独的构造函数。模拟修补您的代码以用模拟替换对象。只需在您的测试方法上使用mock.patch()
装饰器;它将传入对生成的模拟对象的引用。
Both producer.Producer()
and consumer.Consumer()
are then mocked out beforeyou create the instance:
双方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)])
So the moment test_send_data
is called, the mock.patch()
code replaces the producer.Producer
reference with a mock object. Your MyCoordinator
class then uses those mock objects rather than the real code. calling producer.Producer()
returns a new mock object (the same object that mock_producer.return_value
references), etc.
所以在test_send_data
调用的那一刻,mock.patch()
代码producer.Producer
用一个模拟对象替换了引用。MyCoordinator
然后您的类使用这些模拟对象而不是真正的代码。调用producer.Producer()
返回一个新的模拟对象(mock_producer.return_value
引用的同一对象)等。
I've made the assumption that producer
and consumer
are top-level module names. If they are not, provide the full import path. From the mock.patch()
documentation:
我已经假设producer
和consumer
是顶级模块名称。如果不是,请提供完整的导入路径。从mock.patch()
文档:
targetshould 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.
目标应该是形式为 的字符串
'package.module.ClassName'
。目标被导入并且指定的对象替换为新对象,因此目标必须可从您正在调用的环境中导入patch()
。目标是在执行装饰函数时导入的,而不是在装饰时导入。