Home > database >  How can I mock out this python function properly?
How can I mock out this python function properly?

Time:03-16

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

  • Related