如何在不使用Mock的情况下模拟Python方法
我是一名C#开发者,最近开始接触Python,所以现在还不太懂。听说在Python中其实不太需要依赖注入。我被告知可以在代码中直接创建对象,让它们按我想要的方式运行,不过我可以把这些对象的方法指向我在测试中定义的自己的“桩”,据说这样做不需要使用模拟。
这是真的吗?我试过这样做,但总是搞不定。实际上应该怎么做呢?在Python中,如何在不使用模拟库的情况下“桩”一个方法呢?
2 个回答
4
在Python中,函数被称为一等对象,这意味着你可以把任何函数赋值给一个名字:
class Person:
def greetings(self):
return "Hi!"
def happy_greetings(self):
return "Hi! You're awesome!"
mike = Person()
mike.greetings() # "Hi!"
Person.greetings = happy_greetings
mike.greetings() # "Hi! You're awesome!"
可以把方法的名字看作是对某个函数的引用。通过改变这个引用,Python解释器会找到并执行它所指向的函数。不过,我建议你使用一些成熟的模块,比如unittest.mock,因为手动处理这些事情可能会遇到很多问题,比如管理临时对象的范围等等。
35
这里有一个简单的例子。请注意,实际的 getData() 方法并没有被调用。它被一个替代品(也叫“桩”)替代了。
import unittest
class ClassIWantToTest(object):
def getData(self):
print "PRODUCTION getData called"
return "Production code that gets data from server or data file"
def getDataLength(self):
return len(self.getData())
class TestClassIWantToTest(unittest.TestCase):
def testGetDataLength(self):
def mockGetData(self):
print "MOCK getData called"
return "1234"
origGetData = ClassIWantToTest.getData
try:
ClassIWantToTest.getData = mockGetData
myObj = ClassIWantToTest()
self.assertEqual(4, myObj.getDataLength())
finally:
ClassIWantToTest.getData = origGetData
if __name__ == "__main__":
unittest.main()