How can I patch / mock logging.getlogger()
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()
Related videos on Youtube
Philip Ridout
Updated on July 09, 2022Comments
-
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 over 10 yearsWhat mocking library do you use?
-
Philip Ridout over 10 yearsI'm on Python 3.3, so unittest.mock
-
subbu over 5 yearsFacing something similar.. help :) stackoverflow.com/questions/54264007/…
-
-
Philip Ridout over 10 yearsCan't believe it was so simple, just what I was looking for. Thanks for the quick reply too!
-
Jerther about 5 yearsFrom 3.4 on, the test framework includes a self.assertLogs() method! Check it out: stackoverflow.com/a/34920727/2498426
-
Lazerbeak12345 almost 3 yearsThis actually works with @patch format as well. Just prefix your function with
@mock.patch.object(logging.getLogger('path.to.module.under.test'), 'debug')
and give the function the extra argumentmock_debug
.