部分模拟是指在单元测试过程中,部分模拟一个对象,而不改变其实例中未被模拟的部分,这在只需要测试某个方法的情况下非常有用。但在涉及到父子类的情况下,可能会遇到一些问题。
假设有如下的父类和子类:
class Parent:
def foo(self):
print("parent foo")
class Child(Parent):
def bar(self):
self.foo()
print("child bar")
现在我们想要只模拟Child类的bar方法,我们可以使用unittest中的mock模块来部分模拟:
from unittest.mock import patch
class TestChild(unittest.TestCase):
def test_bar(self):
with patch.object(Child, "foo") as mock_foo:
c = Child()
c.bar()
mock_foo.assert_called_once()
然而,mock_foo.assert_called_once()将会失败并报错,因为调用的方法实际上是Parent类中的foo方法,而不是Child类。这是因为一旦覆盖子类中的方法,就无法正确地调用其父类中的同名方法。
解决方法是将被模拟的方法重命名,以避免与父类中同名方法的冲突。例如,我们可以将Child类中的foo方法重命名为_child_foo方法:
class Child(Parent):
def _child_foo(self):
print("child foo")
def bar(self):
self._child_foo()
print("child bar")
现在,我们将它们打包在一起:
class TestChild(unittest.TestCase):
def test_bar(self):
with patch.object(Child, "_child_foo") as mock_foo:
c = Child()
c.bar()
mock_foo.assert_called_once()
现在,我们可以成功地部分模拟Child类的bar方法,而不会影响Parent类中的同名方法。