How to Mock Logging in Python

As you become familiar with software testing and unit testing it can be necessary to assure yourself that information will be logged when your software platform raises an exception or behaves unexpectedly.

In other words, you've developed a new feature and you want to make sure that certain calls to Python's logging module are performed in certain cirumstances.

That's where the mock module comes in: it allows us to mock the Python logging module and assert that certain calls are made. If you're using Python 3.3 (or higher) than you can import from the unittest.mock (documentation) module rather than installing mock from PyPI.

Example of mocking in unit tests

Let's say our code looks like this:

import logging

def check_value(data_dict, value):
    try:
        return data_dict[value] > 10
    except KeyError:
        logging.warn("Data does not contain '%s'", value)
    return False

What we wish to test is that logging.warn is called when the KeyError is raised. So in our unit test we call check_value with parameters in such a way that the KeyError is indeed raised. For example:

import unittest
from my_module import check_value

class MyUnitTest(unittest.TestCase):

    def test_check_value_logs_warning(self):
        check_value({}, 'key')

The idea behind mocking is as follows: instead of calling the real warn function of the logging module we call a fake mocked version and that allows us to keep track of how many times the function is called (if at all).

We can do that using the patch function of the mock library: this specifies what we wish to mock and what the name of the mocked object should be.

We can now update our test by writing:

import unittest
from mock import patch
from my_module import check_value

class MyUnitTest(unittest.TestCase):

    @patch('my_module.logging')
    def test_check_value_logs_warning(self, mock_logging):
        check_value({}, 'key')
        self.assertTrue(mock_logging.warn.called)

if __name__ == '__main__':
    unittest.main()

This unit test passes as the assertion is indeed true. If you modify the code in a way that it no longer logs a warning then you'll find that the assertion in the unit test fails.

Contents © 2014 Simeon Visser