如何提供python单元测试的模拟类方法?
假设我有这样的班级。如何提供python单元测试的模拟类方法?
class SomeProductionProcess(CustomCachedSingleTon):
def loaddata():
"""
Uses an iterator over a large file in Production for the Data pipeline.
"""
pass
现在在测试时间我想改变loaddata()
方法中的逻辑。这将是一个简单的自定义逻辑,不会处理大量数据。
我们如何在测试时间使用Python Mock UnitTest框架提供loaddata()
的自定义实现?
比方说你有一个名为awesome.py和它模块,您有:
import time
class SomeProductionProcess(CustomCachedSingleTon):
def loaddata(self):
time.sleep(30) # simulating a long running process
return 2
那么你的单元测试,你嘲笑loaddata
看起来是这样的:
import unittest
import awesome # your application module
class TestSomeProductionProcess(unittest.TestCase):
"""Example of direct monkey patching"""
def test_loaddata(self):
some_prod_proc = awesome.SomeProductionProcess()
some_prod_proc.loaddata = lambda x: 2 # will return 2 every time called
output = some_prod_proc.loaddata()
expected = 2
self.assertEqual(output, expected)
或者它可能看起来像这样:
import unittest
from mock import patch
import awesome # your application module
class TestSomeProductionProcess(unittest.TestCase):
"""Example of using the mock.patch function"""
@patch.object(awesome.SomeProductionProcess, 'loaddata')
def test_loaddata(self, fake_loaddata):
fake_loaddata.return_value = 2
some_prod_proc = awesome.SomeProductionProcess()
output = some_prod_proc.loaddata()
expected = 2
self.assertEqual(output, expected)
现在,当您运行测试时,loaddata
将不会花费30秒来处理这些测试用例。
要使用结构化的return_value轻松地嘲笑类方法,可以使用unittest.mock.Mock
。
from unittest.mock import Mock
mockObject = SomeProductionProcess
mockObject.loaddata = Mock(return_value=True)
编辑:
由于要模拟出一个自定义实现的方法,你可能只是在测试运行时创建一个自定义的模拟方法的对象和换出原来的方法。
def custom_method(*args, **kwargs):
# do custom implementation
SomeProductionProcess.loaddata = custom_method
我想做一个loaddata方法的自定义实现,而不仅仅是返回值。 – user4654
您可以将loaddata分配给自定义实现。给我一秒钟,我会更新我的答案。 –
这里有一个简单的方法用做模拟
import mock
def new_loaddata(cls, *args, **kwargs):
# Your custom testing override
return 1
def test_SomeProductionProcess():
with mock.patch.object(SomeProductionProcess, 'loaddata', new=new_loaddata):
obj = SomeProductionProcess()
obj.loaddata() # This will call your mock method
我推荐使用pytest
代替unittest
模块,如果你能。它使您的测试代码更加清洁,并减少了大量使用unittest.TestCase
样式测试的样板。
谢谢,所以你提到的方法是根据unittest还是pytest? – user4654
'mock'可以用于任一种。使用'pytest'或'unittest'的区别只是改变了你的测试函数的样子。我的例子使用'pytest'格式,你只需要使用常规函数和内置的'assert'语句。看看@willnx [answer](http://*.com/a/38579804/1547004),看看'unittest'测试的例子。 –
请注意,loaddata()是@classmethod。另外我想提供一个自定义的loaddata()来测试这个类中的另一个方法。 – user4654
考虑到这个问题,'模拟方法'会更加正确,因为当你说'class method'时,隐含了'classmethod'的模拟方法。一个方法总是一个类实例的一部分,一个classmethod是类的一部分。使用装饰器@classmethod使其正确更改方法并添加参数cls。 – msudder