When unit testing Python code with the unittest standard library, what is the proper way to Mock or MagicMock logging from the code that is being tested? Would the approach outlined in the stripped down, simplified example below be considered Pythonically correct?
Tested code:
class FooOperator:
def __init__(self, ..., logging=logging):
self.logging = logging
...
def __get_logging(self):
return self.logging
...
def some_function(self, arg1, arg2):
self.logging.info("First info message")
result = self.some_other_function(arg1=arg1, arg2=arg2)
if result > 0:
# Processing records
...
else:
self.logging.warning(
f"Warning message: No records found for {arg1}, {arg2}"
)
...
self.logging.info("Second logging message")
return True
Unit test:
import unittest
from unittest.mock import MagicMock
import logging
from libraries.foo_operator import FooOperator
class Test_some_function(unittest.TestCase):
def setUp(self):
self.logging = logging
self.dag_info = dict(
name="valid_dag_name",
run_id="valid_dag_run_id",
task="valid_dag_task",
description="valid_dag_description"
)
...
def test_success_logging_warning(self):
sf_op = FooOperator(None, self.dag_info, logging)
sf_op._FooOperator__set_logging(self.logging)
...
expected_result = "something"
self.logging.warning = MagicMock()
...
result = some_function(arg1="valid_arg1", arg2="valid_arg2")
self.assertEqual(result, expected_result)
# Assert for logging WARNING
self.logging.warning.assert_called_once_with(
f"Warning message: No records found for {arg1}, {arg2}"
)
def test_success_logging_info(self):
sf_op = FooOperator(None, self.dag_info, logging)
sf_op._FooOperator__set_logging(self.logging)
...
expected_result = "something"
self.logging.info = MagicMock()
...
result = some_function(arg1="valid_arg1", arg2="valid_arg2")
self.assertEqual(result, expected_result)
# Assert for logging INFO
self.logging.info.assert_has_calls([
call("First info message"),
call("Second info message")
])