I have the following function in a file called my_file.py:
import logging
log = logging.getLogger(__name__)
class MyClass:
def my_func(self):
print("Entered my_func()")
print("log.error = {}".format(log.error))
log.error("Hello World")
When my_func()
is run, I see this output:
Entered my_func()
log.error = <bound method ProcessAwareLogger.error of <celery.utils.log.ProcessAwareLogger object at 0x7fd52d4f0d50>>
I want to write a unit-test case to check that whenever my_func()
is called, log.error()
is called with the argument "Hello World"
.
So my test case looks like this:
import mock
from my_file import MyClass
@mock.patch("my_file.logging.error")
def test_parse_response_with_error(self, mock_log_error):
m = MyClass()
m.my_func()
mock_log_error.assert_called_once_with("Hello World")
When I run this test case, I get the error: AssertionError: Expected to be called once. Called 0 times.
So my patch apparently didn't work. Did I specify the path my_file.logging.error
wrong? How can I make this work properly so that the unit-test case passes?
CodePudding user response:
You mocked the wrong thing. log.error
creates a bound method that is distinct from logging.error
, and that method already has a reference to the "real" logging.error
saved before your patch was created.
Instead, mock the error
attribute of the Logger
instance directly.
@mock.patch.object(my_file.log, 'error'):
def test_it(self, mock_log_error):
m = MyClass()
m.my_func()
mock_log_error.assert_called_once_with("Hello World")
(It's possible that patching logging.error
before importing my_file
might work.)