如何模拟工厂静态方法以返回模拟对象?

时间:2020-12-18 20:22:10

标签: mocking pytest static-methods

我有以下课程:

class Toto():

    @staticmethod
    def factory():
        return Toto("Toto")

    def __init__(self, name):
        self.name = name

    def get_name(self):
        return self.name

    @staticmethod
    def method_to_test():
      # do stuff
      toto_object = Toto.factory()
      # do stuff with toto_object
      toto_object.get_name()

我想 mock factoryToto 方法,所以当它被调用时,它返回一个 Toto 的模拟。

然后应该通过以下测试:

from junit.toto import Toto


def test_toto_method_to_test(mocked):
    mocked_toto = mocker.patch("junit.toto.Toto")
    mocked_toto.get_name.return_value = "Tata"
    mocked_toto_factory = mocker.patch(__name__ + ".Toto.factory")
    mocked_toto_factory.return_value = mocked_junit_xml_generator

    Toto.method_to_test()
    mocked_toto.get_name.assert_called()

    #mocked_toto and mock in the tested method are not the same -> FAIL

目前,我无法正确模拟工厂方法。

1 个答案:

答案 0 :(得分:1)

问题在于,在您的测试中,您没有使用 Toto 的模拟实例,它位于 Toto 模块中,而是在测试本身中导入的实例({{1} })。要解决此问题,有两种可能性:使用模拟对象,或在测试本身中模拟引用。

要使用模拟对象,您应导入包含要模拟的对象的模块:

from ... import Toto

如果使用 import junit def test_toto_mock(mocker): mocked_toto = mocker.patch("junit.toto.Toto") mocked_toto.get_name.return_value = "Tata" assert mocked_toto.get_name() == "Tata" mocked_toto.factory.return_value = mocked_toto # use the same reference that you have mocked assert junit.toto.Toto.factory().get_name() == "Tata" 导入对象,则必须在测试模块中修补引用,from ... import 包含当前模块的名称:

__name__

如果出于某种原因您需要模拟两个实例,如评论中所述,您也可以这样做:

from junit.toto import ToTo

def test_toto_mock(mocker):
    # mock the reference in the test itself
    mocked_toto = mocker.patch(__name__ + ".Toto")
    mocked_toto.get_name.return_value = "Tata"

    assert mocked_toto.get_name() == "Tata"

    mocked_toto.factory.return_value = mocked_toto
    # use the local reference of ToTo
    assert Toto.factory().get_name() == "Tata"

请阅读where to patch了解更多信息。