如何在不使用Mock的情况下模拟Python方法

15 投票
2 回答
18346 浏览
提问于 2025-04-16 05:20

我是一名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()

撰写回答