Mocking function imported to many locations

Viewed 45

I want to mock a function in every place it's imported.

Example

Say I have

# foo.py

def send_email():
    call_email_service()
# bar1.py
from foo import send_email

def my_func():
    ...
    send_email()

and many other files using send_email. I want a fixture to mock all usages of send_email.

Current best solution

Trying to patch 'foo.send_email' does not work since you need to patch it the namespace it's used in (namely, I'd have to patch 'bar1.send_email').

The best solution I have is rewriting the code like this:

# foo.py

def send_email():
    _send_email_mockable()

def _send_email_mockable():
    call_email_service()

and writing a fixture like:

@pytest.fixture(autouse=True)
def _mock_email_service():
    with patch('foo._send_email_mockable', autospec=True):
        yield

That indeed works, but I'd prefer the test logic not to creep into my main logic if possible, and if send_email has a complicated function signature, I have to repeat it twice.

1 Answers

Change your import statements to the following:

# bar1.py

# Previous way
from foo import send_email

# New way
import foo

def my_func():
    ...
    foo.send_email()

This will allow the mock to patch foo namespace, prior to loading of send_email in your destination files.

Related