pythonunit-testingmockingmagicmock

Python Mock: Raising Error for function of Mocked Class


I'm trying to test some code that create or changes directories and files based on some inputs. My issue is raising exceptions when a method of a mocked object is called. For example, say I have some code:

def create_if_not_exists(dest):
    dir = os.path.dirname(dest)
    if not dir:
        # create if it doesn't exist
        try:
           os.makedirs(os.path.dirname(dest))
        except OSError:
           pass # Nevermind what goes here, it's unimportant to the question

My unit test follows these ideas:

@patch('my.package.os')
def test_create_dir_if_not_exists(self, mock_os):
    # dirname return None means that the path not exists
    mock_os.path.dirname.return_value = None
    # by following instruction I want to raise an OSError Exception
    mock_os.makedirs.raiseError.side_effect = OSError()

    with self.assertRaises(OSError)
        create_if_not_exists('test')

This setup returns AssertionError: OSError not raised but my understanding is it should raise the error when the makedirs call is made in the actual (non-test) method. Is my understanding incorrect?


Solution

  • Try with the following patch in the test file:

    @patch('my.package.os.path.dirname')
    @patch('my.package.os.makedirs')
    def test_create_dir_if_not_exists(self, mock_os_makedirs, mock_os_path_dirname):
        mock_os_path_dirname.return_value = None
        # mock_os.makedirs.raiseError.side_effect = OSError() <--- REMOVE raiseError
        mock_os_makedirs.side_effect = OSError()
    
        with self.assertRaises(OSError)
            create_if_not_exists('test')
    

    Furthermore your function create_if_not_exists() must not to catch the OSError exception; so your create_if_not_exists() function must be modified as followed:

    import os
    
    def create_if_not_exists(dest):
        dir = os.path.dirname(dest)
        if not dir:
            # create if it doesn't exist
            #try:
                os.makedirs(os.path.dirname(dest))
            #except OSError:
            #   pass # Nevermind what goes here, it's unimportant to the question
    

    otherwise the test fails.

    Also your test was good

    In your test the only problem was the instruction:

    mock_os.makedirs.raiseError.side_effect = OSError()
    

    So an other solution for your test is:

    @patch('my.package.os')
    def test_create_dir_if_not_exists(self, mock_os):
        mock_os.path.dirname.return_value = None
        #mock_os.makedirs.raiseError.side_effect = OSError() <--- REMOVE raiseError
        mock_os.makedirs.side_effect = OSError()
    
        with self.assertRaises(OSError):
            create_if_not_exists('test')