在Python中,禁用单元测试中特定代码的好方法是什么?
总的来说,我希望尽量少禁用代码,并且要明确:我不想让被测试的代码自己决定它是不是在测试中,我希望测试能够告诉那段代码“嘿,顺便说一下,我正在运行单元测试,你能不能不要调用solr,而是把你本来要发送给solr的内容放在这里,这样我可以检查一下”。我有一些想法,但我不太喜欢它们,我希望能找到一种好的、符合Python风格的方法来实现这个。
6 个回答
1
我之前遇到的一个大问题是关于依赖注入的操作。我现在已经搞明白这个部分了。
我需要在两个地方以完全相同的方式导入模块,这样才能成功地注入新的代码。例如,如果我有以下代码想要禁用:
from foo_service.foo import solr
solr.add(spam)
我在我的测试运行器中似乎无法做到这一点:
from foo import solr
solr = mock_object
Python 解释器可能把模块 foo_service.foo
和 foo
当作不同的东西来处理。我把 from foo import solr
改成了更明确的 from foo_service.foo import solr
,结果我的模拟对象成功注入了。
8
你可以使用模拟对象来拦截那些你不想执行的方法调用。比如,你有一个类A
,在测试时你不想调用它的no()
方法。
class A:
def do(self):
print('do')
def no(self):
print('no')
你可以创建一个模拟对象,它继承自A
,并重写no()
方法,让它什么都不做。
class MockA(A):
def no(self):
pass
这样,在你的测试代码中,你就可以创建MockA
对象,而不是A
对象。另一种模拟的方法是让A
和MockA
实现一个共同的接口,比如InterfaceA
。
市面上有很多模拟框架可以使用。可以参考StackOverflow: Python 模拟框架。
特别推荐查看:谷歌的 Python 模拟框架。
5
在你的单元测试中,使用Michael Foord的Mock库,步骤如下:
from mock import Mock
class Person(object):
def __init__(self, name):
super(Person, self).__init__()
self.name = name
def say(self, str):
print "%s says \"%s\"" % (self.name, str)
...
#In your unit test....
#create the class as normal
person = Person("Bob")
#now mock all of person's methods/attributes
person = Mock(spec=person)
#talkto is some function you are testing
talkTo(person)
#make sure the Person class's say method was called
self.assertTrue(person.say.called, "Person wasn't asked to talk")
#make sure the person said "Hello"
args = ("Hello")
keywargs = {}
self.assertEquals(person.say.call_args, (args, keywargs), "Person did not say hello")