很难从一个人造实例中猜测出最佳方法。当只需使用所需的模拟并尽可能多地使用真实对象时,这是最好的选择。但这是一个权衡游戏,当创建真实对象很困难且依赖项非常复杂时,模拟可以成为非常强大的工具。此外,模拟会给您提供许多测试点。但是,这需要付出代价:有时,通过使用模拟,您可能会隐藏一些仅在集成测试中才能引发的错误。
对于您的情况,我建议最好只模拟
a
并设置
fetch
的返回值。您还可以测试
a.initialize()
的调用。
如果您的目标只是模拟
a.initialize()
(当然也包括
a.fetch()
,因为没有
initialize()
,
a.fetch()
没有意义),最好的方法是只
patch
a
对象。
无论如何,最后一个测试是关于修补超类。在您的情况下,这有点棘手,您必须同时修补
__init__
并注入
a
,
b
属性。如果您担心
GenericClass
在init中做了什么,您必须直接修补
__init__
方法:修补类是无用的,因为它的引用已经在
SpecificClass
定义中解析(它由
super
而不是
GenericClass.__init__(...)
解析)。也许在实际代码中,您应该针对
a
和
b
的只读属性进行斗争:同样,如果您可以使用真实对象并尽可能减少修补的方法/对象,那么这是最佳选择。我喜欢
mock
框架,但有时使用它不是最好的选择。
还有一件事:我使用
patch.multiple
只是为了有一个更紧凑的示例,但使用两个
patch.object
修补方法也可以完成相同的工作。
import unittest
from mock import Mock, patch, DEFAULT, PropertyMock
from specific import SpecificClass
class A():
def initialize(self):
raise Exception("Too slow for tests!!!!")
def fetch(self):
return "INVALID"
class MyTestCase(unittest.TestCase):
def test_specific_method(self):
a = A()
with patch.multiple(a, initialize=DEFAULT, fetch=DEFAULT) as mocks:
mock_initialize, mock_fetch = mocks["initialize"], mocks["fetch"]
mock_fetch.return_value = "a"
sc = SpecificClass(a, "b", "c")
self.assertEqual("dcbappenda", sc.specific_method("d"))
mock_initialize.assert_called_with()
def test_sanity_check(self):
a = A()
sc = SpecificClass(a, "b", "c")
self.assertRaises(Exception, sc.specific_method, "d")
@patch("specific.GenericClass.__init__", autospec=True, return_value=None)
def test_super_class(self, mock_init):
sc = SpecificClass("a", "b", "c")
mock_init.assert_called_with(sc, "a", "b")
sc.a = Mock()
sc.b = "b"
sc.a.fetch.return_value = "a"
self.assertEqual("dcba", sc.specific_method("d"))
sc.a.initialize.assert_called_with()
a
在self.a
中存储的假设,这在这种情况下是正确的,但我不想依赖于来自外部库的类的内部逻辑。我们是否应该使用patch
显式地模拟self.a
呢? - poros