I have some unittests that I am running on a class, ClassA
. This class has methods that call ClassB
. ClassA
and ClassB
are in separate modules, class_A.py
and class_B.py
. Both of these modules have logger
functions that are available globally within that module.
During my test of the methods of ClassA
I want to suppress the logging messages. Using mock.patch
it is straightforward to do this for the logger in class_A.py
. But I have not found a way to patch the logger in class_B.py
.
Here is some sample code:
unittest_file.py
import unittest
import class_A
class TestClassA(unittest.TestCase):
def setUp(self):
pass
def test_method(self):
my_class_A = class_A.ClassA()
my_class_A.run_method()
def tearDown(self):
pass
class_A.py
import logging
from class_B import ClassB
logger = logging.getLogger(__name__)
class ClassA:
run_method(self):
my_class_B = ClassB()
my_class_B.do_something()
logger.info("Running method on Class A")
class_B.py
import logging
logger = logging.getLogger(__name__)
class ClassB:
do_something(self):
logger.info("Doing something on Class B")
To patch the logger in class_A.py
I can add @patch('__main__.unittest_file.ClassA.logger', autospec=True)
as a decorator to the test_method()
method.
But I don't have direct access to the logger in class_B.py
to patch it as well.
The closest I have come to a solution is this:
@patch(eval('__main__.unittest_file.class_A.ClassB.__module__')['logger'])
but the eval()
function applied to the module name doesn't preserve the import location, so it doesn't patch the logger in the right namespace.
I know I could easily solve this by changing the import
statement in class_A.py
to import class_B
instead of from class_B import ClassB
, but I don't want to edit the code in class_A.py
or class_B.py
, so that's not the answer I'm looking for.
I also know there are ways around this by disabling logging, as in this question but I am more interested in being able to fine-tune the control I have over different parts of the code to be tested, so that's not the answer I'm looking for either.
My question is: Is there a way that I can navigate from an imported object to other objects in its parent module, while staying in the same namespace?
For me simply patching class_A.logger
and class_B.logger
works, e.g.
import unittest
from unittest import mock
class TestCaseA(unittest.TestCase):
@mock.patch('class_A.logger')
@mock.patch('class_B.logger')
def test_method(self, mockedA, mockedB):
my_class_A = ClassA()
my_class_A.run_method()
Both loggers don't output log messsages anymore.