用模拟修补超类方法

问题描述 投票:4回答:1

这里有许多类似的问题,涉及如何在Python中修补类的超类以进行测试。我已经从他们那里收集了一些想法,但是我仍然不在需要的地方。

想象一下我有两个基类:

class Foo(object):
    def something(self, a):
        return a + 1

class Bar(object):
    def mixin(self):
        print("Hello!")

现在,我这样定义要测试的类:

class Quux(Foo, Bar):
    def something(self, a):
        self.mixin()
        return super().something(a) + 2

说我想测试是否已调用[C​​0],并且要替换模拟的mixin的返回值,但重要的是(但有必要)我不想更改任何控制流或逻辑Foo.something。假定修补超类“工作正常”,我尝试了Quux.something

unittest.mock.patch

这不起作用:在实例化with patch("__main__.Foo", spec=True) as mock_foo: with patch("__main__.Bar", spec=True) as mock_bar: mock_foo.something.return_value = 123 q = Quux() assert q.something(0) == 125 mock_bar.mixin.assert_called_once() 时,不会嘲笑somethingmixin的超类定义,这并不奇怪,因为在修补程序之前定义了类的继承。

至少可以通过显式设置它来解决Quux问题:

mixin

但是,类似的方法不适用于被覆盖的方法# This works to mock the mixin method q = Quux() setattr(q, "mixin", mock_bar.mixin)

[正如我提到的,对该问题的其他答案建议使用模拟覆盖somethingQuux值。但是,这根本不起作用,因为__bases__必须是一个类的元组,并且模拟的类似乎只是原始的:

__bases__

[其他答案建议覆盖# This doesn't do what I want Quux.__bases__ = (mock_foo.__class__, mock_bar.__class__) q = Quux() does可行,但是我觉得这有点危险,因为任何您不想打补丁的对super的调用都可能会破坏您的工作。

所以有什么比我做的更好的方法了:

super
python-3.x unit-testing mocking patch superclass
1个回答
0
投票

实际上很简单-子类将包含对原始类的引用内部结构(公共可见属性with patch("builtins.super") as mock_super: mock_foo = MagicMock(spec=Foo) mock_foo.something.return_value = 123 mock_super.return_value = mock_foo mock_bar = MagicMock(spec=Bar) q = Quux() setattr(q, "mixin", mock_bar.mixin) assert q.something(0) == 125 mock_bar.mixin.assert_called_once() __bases__)。模拟那些基类时,该引用不会更改-模拟只会显式影响使用这些对象的对象,而补丁是“打开”的。换句话说,仅当__mro__类本身在Quux块内定义时,才使用它们。而且这也不起作用,因为替换类的“模拟”对象不能是适当的超类。

但是,解决方法和正确的方法很简单-您只需要模拟要替换的the methods,而不是类。

这个问题现在有点老了,希望您继续前进,但是正确的做法是:

with
© www.soinside.com 2019 - 2024. All rights reserved.