How can I patch / mock logging.getlogger()

Question:

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!

Asked By: Philip Ridout

||

Answers:

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')
Answered By: chepner

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

Answered By: hwjp

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')
Answered By: emcas88

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

Even simpler…

Just patch the logging module itself.

# File foo.py

import logging


log = logging.getLogger(__name__)


def main():
    log.debug('Init')



# File foo_test.py

from unittest.mock import patch

import foo


@patch.object(foo, 'logging')
def test_log_debug_called(logging):
    foo.main()
    logging.debug.assert_called_with('Init')
Answered By: Chris Collett

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')
Answered By: sankalp