Search code examples
pythonpython-unittestpython-3.8

python3.8 delete file unittests


I have a utility function for removing a file as below. And I intend to write unittest cases for it.

def delete_file_name(file_name, logger):
    """
    Deletes given file name
    """
    try:
        os.remove(file_name)
        logger.info("Deleted file: %s", file_name)
    except FileNotFoundError:
        logger.error("Error: File not found %s", file_name)
    except PermissionError:
        logger.error("Invalid permissions while deleting: %s", file_name)
    except OSError as exc:
        logger.error("Error while deleting %s: %s", exc.filename, exc.strerror)

How do I go about writing test cases? Considering that these exceptions are not really raised but handled by a log message. Any pointers on how the assertions would be?

Tried below but it shows an error that exception is not raised.

    @patch('os.remove')
    def test_file_delete_with_os_error(self, mock_remove):
        mock_remove.side_effect = OSError
        with self.assertRaises(OSError):
            delete_file_name('abc.txt', logging.getLogger('test'))

Solution

  • Because you control the logger that's passed to the tested function, you can redirect the output to a custom io.StringIO object:

    import logging
    import unittest
    from unittest.mock import patch
    
    # simulated, adjust to your needs
    from my_module import delete_file_name
    
    class TestSomething(unittest.TestCase):
        def setUp(self):
            self.stream = io.StringIO()
            self.logger = logging.getLogger('test')
            self.stream_handler = logging.StreamHandler(self.stream)
            self.logger.addHandler(self.stream_handler)
    
        def tearDown(self):
            self.logger.removeHandler(self.stream_handler)
    
        @patch('os.remove')
        def test_delte_file_os_error(self, mock_remove):
            mock_remove.side_effect = OSError
            delete_file_name('abc.txt', self.logger)
    
            self.stream.seek(0)
            self.assertEqual(self.stream.read(), 'Error while deleting None: None\n')
    

    As you can see, you can then retrieve the output of the logger and check if it is equal to what you expect. (In this example I put Error while deleting None: None as this is the output the side_effect you currently have in place gives)