如何模拟工厂静态方法以便 return 模拟对象?
How to mock a factory static method in order to return a mocked object?
我有以下 class:
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
Toto
的 factory
方法,所以当它被调用时,它 returns 是 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
目前,我无法正确模拟工厂方法。
问题在于,在您的测试中,您没有使用位于 Toto
模块中的 Toto
的模拟实例,而是在测试本身中导入的实例(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"
如果由于某种原因你需要模拟两个实例,正如评论中提到的,你也可以这样做:
import junit
from junit.toto import ToTo
def test_toto_mock(mocker):
mocked_toto = mocker.patch(__name__ + ".Toto")
# replace the object in the other module with the same mock
mocker.patch("junit.toto.Toto", mocked_toto)
mocked_toto.get_name.return_value = "Tata"
assert mocked_toto.get_name() == "Tata"
mocked_toto.factory.return_value = mocked_toto
assert Toto.factory().get_name() == "Tata"
assert junit.toto.Toto.factory().get_name() == "Tata"
请阅读 where to patch 了解更多信息。
我有以下 class:
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
Toto
的 factory
方法,所以当它被调用时,它 returns 是 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
目前,我无法正确模拟工厂方法。
问题在于,在您的测试中,您没有使用位于 Toto
模块中的 Toto
的模拟实例,而是在测试本身中导入的实例(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"
如果由于某种原因你需要模拟两个实例,正如评论中提到的,你也可以这样做:
import junit
from junit.toto import ToTo
def test_toto_mock(mocker):
mocked_toto = mocker.patch(__name__ + ".Toto")
# replace the object in the other module with the same mock
mocker.patch("junit.toto.Toto", mocked_toto)
mocked_toto.get_name.return_value = "Tata"
assert mocked_toto.get_name() == "Tata"
mocked_toto.factory.return_value = mocked_toto
assert Toto.factory().get_name() == "Tata"
assert junit.toto.Toto.factory().get_name() == "Tata"
请阅读 where to patch 了解更多信息。