使用mock修补不存在的属性

Bre*_*bel 11 python testing unit-testing mocking pytest

我正在尝试测试一个上下文管理器,它使用一个使用一些__getattr__魔法的类来解析几个实际上不存在于类中的属性.我遇到了一个问题,在尝试修补类时,mock会引发一个AttributeError.

我要修补的对象的简化示例.

class MyClass(object):
    def __getattr__(self, attr):
        if attr == 'myfunc':
            return lambda:return None
        raise AttributeError('error')


class MyContextManager(object):
    def __init__(self):
        super(MyContextManager, self).__init__()
        self.myclass = MyClass()

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.myclass.myfunc()
Run Code Online (Sandbox Code Playgroud)

测试代码

def test_MyContextManager():
    with patch.object(MyClass, 'myfunc', return_value=None) as mock_obj:
        with MyContextManager():
             pass

    # Do some tests on mock object
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

AttributeError: <class 'MyClass'> does not have the attribute 'myfunc'
Run Code Online (Sandbox Code Playgroud)

我能够执行此操作并运行测试,但它不会自动恢复属性(或者只是在这种情况下删除mock属性):

MyClass.myfunc= Mock(return_value=None)
Run Code Online (Sandbox Code Playgroud)

我愿意使用除了mock之外的另一个库来实现这一点.我也在使用pytest.

Mic*_*ico 19

要在这些测试中使用补丁,您应该使用create将强制创建属性的参数(如果不存在).

所以你的测试应该做这样的事情:

def test_MyContextManager():
    with patch.object(MyClass, 'myfunc', create=True, return_value=None) as mock_obj:
        with MyContextManager():
             pass
Run Code Online (Sandbox Code Playgroud)