无法正确修补对象的属性

时间:2019-07-22 23:44:41

标签: python unit-testing mocking python-mock

我有一个Python模块,如下所示:

# src/exec.py

class A:

    def run(self, stuff):
        b = B(stuff.x)

class B:
    def __init__(self, x):
        self.obj = self.create_some_obj()

我试图独立测试类A的一部分,为此我需要用伪造的对象替换obj中的B。我这样做如下:

# test/test_execs.py

import exec as ex

class FakeObjForB:
    def __init__(self):
        # some init

class TestClass:

    @patch.object(ex.B, 'obj', FakeObjForB())
    def test_with_fake_obj(self):
        a = ex.A()
        a.run()
        # assert something about the state of a that depends on the b inside its run method

运行此测试会给我错误:AttributeError: <class 'B'> does not have the attribute 'obj'。我尝试用@patch@patch.object(ex.B, 'obj', FakeObjForB(), create=True)装饰器替换该行。但是,这会导致b.obj使用实际的定义,而不是FakeObjForB,这反过来导致test_with_fake_obj中的断言错误。关于我在这里做错了什么的任何线索吗?

1 个答案:

答案 0 :(得分:0)

在您的示例中,您正在修补B类,这是作为第一个参数传递的对象。该类未在类级别上声明obj属性,因此引发AttributeError。当您提供create=True时,它不会抱怨,因为该参数允许在需要/访问时动态创建obj属性。但是,这永远不会发生,因为该属性的第一个“访问”是它的实际创建-从未发生过动态模拟。

一种解决方案是实际修补将其返回值分配给obj属性的方法,例如:

@patch.object(ex.B, 'create_some_obj', FakeObjForB())