<p>这是我很长时间以来一直在努力解决的问题,但我想我终于找到了解决办法。</p>
<p>正如您已经注意到的,如果您试图用Mock替换基类,那么您试图测试的类将变成Mock,这将破坏您测试它的能力。解决方案是只模拟基类的方法,而不是整个基类本身,但这说起来容易做起来难:在逐个测试的基础上逐个模拟每个方法很容易出错。</p>
<p>相反,我所做的是创建一个扫描另一个类的类,并将与另一个类上的方法匹配的<code>Mock()</code>赋值给它自己。然后可以在测试中使用这个类代替真正的基类。</p>
<p>这是假班:</p>
<pre><code>class Fake(object):
"""Create Mock()ed methods that match another class's methods."""
@classmethod
def imitate(cls, *others):
for other in others:
for name in other.__dict__:
try:
setattr(cls, name, Mock())
except (TypeError, AttributeError):
pass
return cls
</code></pre>
<p>例如,您可能有一些这样的代码(抱歉,这有点做作,假设<code>BaseClass</code>和<code>SecondClass</code>正在做一些非琐碎的工作,包含许多方法,甚至根本不一定由您定义):</p>
<pre><code>class BaseClass:
def do_expensive_calculation(self):
return 5 + 5
class SecondClass:
def do_second_calculation(self):
return 2 * 2
class MyClass(BaseClass, SecondClass):
def my_calculation(self):
return self.do_expensive_calculation(), self.do_second_calculation()
</code></pre>
<p>然后您就可以编写如下测试:</p>
<pre><code>class MyTestCase(unittest.TestCase):
def setUp(self):
MyClass.__bases__ = (Fake.imitate(BaseClass, SecondBase),)
def test_my_methods_only(self):
myclass = MyClass()
self.assertEqual(myclass.my_calculation(), (
myclass.do_expensive_calculation.return_value,
myclass.do_second_calculation.return_value,
))
myclass.do_expensive_calculation.assert_called_once_with()
myclass.do_second_calculation.assert_called_once_with()
</code></pre>
<p>因此,基类上存在的方法仍然可用作您可以交互的mock,但是您的类本身并没有成为mock。</p>
<p>我很小心地确保这在python2和python3中都有效。</p>