Using mock to patch a non-existing attribute

14,464

To use patch in these kind of tests you should use create parameter that will force to create the attribute if not exist.

So your test should do something like this:

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

Related videos on Youtube

Brendan Abel
Author by

Brendan Abel

Designer, Engineer, Programmer Python, Javascript, 3D Scripting Languages, C++, SQL 15+ years in the Film and Games Industry

Updated on June 15, 2022

Comments

  • Brendan Abel
    Brendan Abel almost 2 years

    I'm trying to test a context manager that makes use of a class that uses some __getattr__ magic to resolve several attributes which don't actually exist on the class. I'm running into a problem where mock is raising an AttributeError when trying to patch the class.

    Simplified example of objects I want to patch.

    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()
    

    Test code

    def test_MyContextManager():
        with patch.object(MyClass, 'myfunc', return_value=None) as mock_obj:
            with MyContextManager():
                 pass
    
        # Do some tests on mock object
    

    Here is the error I get:

    AttributeError: <class 'MyClass'> does not have the attribute 'myfunc'
    

    I'm able to do this and run the test, but it doesn't restore the attribute (or simply remove the mock attribute in this case) automatically:

    MyClass.myfunc= Mock(return_value=None)
    

    I'm open to using another library besides mock to achieve this. I'm also using pytest.