How can I patch / mock logging.getlogger()

29,639

Solution 1

You can use patch.object() on the actual logging object. that lets you verify that you're using the correct logger too:

logger = logging.getLogger('path.to.module.under.test')
with mock.patch.object(logger, 'debug') as mock_debug:
    run_code_under_test()
    mock_debug.assert_called_once_with('Init')

Alternatively, if you're using Pytest, then it already has a fixture that captures logs for you:

def test_bar(caplog):
    with caplog.at_level(logging.DEBUG):
        run_code_under_test()
    assert "Init" in caplog.text
    # or, if you really need to check the log-level
    assert caplog.records[-1].message == "Init"
    assert caplog.records[-1].levelname == "DEBUG"

More info in the pytest docs on logging

Solution 2

Assuming log is a global variable in a module mymod, you want to mock the actual instance that getLogger returned, which is what invokes debug. Then, you can check if log.debug was called with the correct argument.

with mock.patch('mymod.log') as log_mock:
    # test code
    log_mock.debug.assert_called_with('Init')

Solution 3

I am late for this question but another of way to achieve it is:

@patch('package_name.module_name.log')
def test_log_in_A(self, mocked_log):

    a = A()
    mocked_log.debug.assert_called_once_with('Init')

Solution 4

This also works:

from unittest.mock import patch

class Test(TestCase):
    def test_logger(self):
        with patch('logging.Logger.warning') as mocked_logger:
            call_func()
            mocked_logger.assert_called_once_with('log')

Solution 5

Here is a complete example

"""
Source to test
"""
import logging

logger = logging.getLogger("abc")

def my_fonction():
    logger.warning("Oops")

"""
Testing part
"""
import unittest
from unittest.mock import patch, MagicMock

abc_logger = logging.getLogger("abc")

class TestApp(unittest.TestCase):

    @patch.object(abc_logger, "warning", MagicMock())
    def test_my_fonction(self):
        # When
        my_fonction()
        # Then
        abc_logger.warning.assert_called_once()

Share:
29,639

Related videos on Youtube

Philip Ridout
Author by

Philip Ridout

Updated on July 09, 2022

Comments

  • Philip Ridout
    Philip Ridout almost 2 years

    I have this code that I want to test:

    log = logging.getLogger(__name__)
    
    
    class A(object):
        def __init__(self):
            log.debug('Init')
    

    but I cannot figure out how to assert that log.debug was called with 'Init'

    I tried patching logger but inspecting it I only found a getLogger mock.

    I'm sure its simple, but I just cant figure it!

    Thanks in advance for any and all help!

    • Martijn Pieters
      Martijn Pieters over 10 years
      What mocking library do you use?
    • Philip Ridout
      Philip Ridout over 10 years
      I'm on Python 3.3, so unittest.mock
    • subbu
      subbu over 5 years
      Facing something similar.. help :) stackoverflow.com/questions/54264007/…
  • Philip Ridout
    Philip Ridout over 10 years
    Can't believe it was so simple, just what I was looking for. Thanks for the quick reply too!
  • Jerther
    Jerther about 5 years
    From 3.4 on, the test framework includes a self.assertLogs() method! Check it out: stackoverflow.com/a/34920727/2498426
  • Lazerbeak12345
    Lazerbeak12345 almost 3 years
    This actually works with @patch format as well. Just prefix your function with @mock.patch.object(logging.getLogger('path.to.module.under.t‌​est'), 'debug') and give the function the extra argument mock_debug.