Since you are using pytest, I would suggest using pytest's built-in 'monkeypatch' fixture.

Consider this simple setup:

We define the function to be mocked.

"""`my_library.py` defining 'foo'."""


def foo(*args, **kwargs):
    """Some function that we're going to mock."""
    return args, kwargs

And in a separate file the class that calls the function.

"""`my_module` defining MyClass."""
from my_library import foo


class MyClass:
    """Some class used to demonstrate mocking imported functions."""
    def should_call_foo(self, *args, **kwargs):
        return foo(*args, **kwargs)

We mock the function where it is used using the 'monkeypatch' fixture

"""`test_my_module.py` testing MyClass from 'my_module.py'"""
from unittest.mock import Mock

import pytest

from my_module import MyClass


def test_mocking_foo(monkeypatch):
    """Mock 'my_module.foo' and test that it was called by the instance of
    MyClass.
    """
    my_mock = Mock()
    monkeypatch.setattr('my_module.foo', my_mock)

    MyClass().should_call_foo(1, 2, a=3, b=4)

    my_mock.assert_called_once_with(1, 2, a=3, b=4)

We could also factor out the mocking into its own fixture if you want to reuse it.

@pytest.fixture
def mocked_foo(monkeypatch):
    """Fixture that will mock 'my_module.foo' and return the mock."""
    my_mock = Mock()
    monkeypatch.setattr('my_module.foo', my_mock)
    return my_mock


def test_mocking_foo_in_fixture(mocked_foo):
    """Using the 'mocked_foo' fixture to test that 'my_module.foo' was called
    by the instance of MyClass."""
    MyClass().should_call_foo(1, 2, a=3, b=4)

    mocked_foo.assert_called_once_with(1, 2, a=3, b=4)
Answer from NSteinhoff on Stack Overflow
Top answer
1 of 3
18

Since you are using pytest, I would suggest using pytest's built-in 'monkeypatch' fixture.

Consider this simple setup:

We define the function to be mocked.

"""`my_library.py` defining 'foo'."""


def foo(*args, **kwargs):
    """Some function that we're going to mock."""
    return args, kwargs

And in a separate file the class that calls the function.

"""`my_module` defining MyClass."""
from my_library import foo


class MyClass:
    """Some class used to demonstrate mocking imported functions."""
    def should_call_foo(self, *args, **kwargs):
        return foo(*args, **kwargs)

We mock the function where it is used using the 'monkeypatch' fixture

"""`test_my_module.py` testing MyClass from 'my_module.py'"""
from unittest.mock import Mock

import pytest

from my_module import MyClass


def test_mocking_foo(monkeypatch):
    """Mock 'my_module.foo' and test that it was called by the instance of
    MyClass.
    """
    my_mock = Mock()
    monkeypatch.setattr('my_module.foo', my_mock)

    MyClass().should_call_foo(1, 2, a=3, b=4)

    my_mock.assert_called_once_with(1, 2, a=3, b=4)

We could also factor out the mocking into its own fixture if you want to reuse it.

@pytest.fixture
def mocked_foo(monkeypatch):
    """Fixture that will mock 'my_module.foo' and return the mock."""
    my_mock = Mock()
    monkeypatch.setattr('my_module.foo', my_mock)
    return my_mock


def test_mocking_foo_in_fixture(mocked_foo):
    """Using the 'mocked_foo' fixture to test that 'my_module.foo' was called
    by the instance of MyClass."""
    MyClass().should_call_foo(1, 2, a=3, b=4)

    mocked_foo.assert_called_once_with(1, 2, a=3, b=4)
2 of 3
12

What you are mocking with the line emails.send_email = MagicMock() is the function

class CarsEmails:

    def send_email(self):
        ...

that you don't have. This line will thus only add a new function to your emails object. However, this function is not called from your code and the assignment will have no effect at all. Instead, you should mock the function send_email from the cars.lib.email module.

mocking the function where it is used

Once you have imported the function send_email via from cars.lib.email import send_email in your module format_email.py, it becomes available under the name format_email.send_email. Since you know the function is called there, you can mock it under its new name:

from unittest.mock import patch

from format_email import CarsEmails

@pytest.mark.parametrize("test_input,expected_output", test_data)
def test_email_payload_formatting(config, test_input, expected_output):
    emails = CarsEmails(email_client=MagicMock(), config=config)
    with patch('format_email.send_email') as mocked_send:
        emails.send_cars_email(*test_input)
        mocked_send.assert_called_with(*expected_output)

mocking the function where it is defined

Update:

It really helps to read the section Where to patch in the unittest docs (also see the comment from Martijn Pieters suggesting it):

The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.

So stick with the mocking of the function in usage places and don't start with refreshing the imports or aligning them in correct order. Even when there should be some obscure usecase when the source code of format_email would be inaccessible for some reason (like when it is a cythonized/compiled C/C++ extension module), you still have only two possible ways of doing the import, so just try out both mocking possibilities as described in Where to patch and use the one that succeeds.

Original answer:

You can also mock send_email function in its original module:

with patch('cars.lib.email.send_email') as mocked_send:
    ...

but be aware that if you have called the import of send_email in format_email.py before the patching, patching cars.lib.email won't have any effect on code in format_email since the function is already imported, so the mocked_send in the example below won't be called:

from format_email import CarsEmails

...

emails = CarsEmails(email_client=MagicMock(), config=config)
with patch('cars.lib.email.send_email') as mocked_send:
    emails.send_cars_email(*test_input)
    mocked_send.assert_called_with(*expected_output)

To fix that, you should either import format_email for the first time after the patch of cars.lib.email:

with patch('cars.lib.email.send_email') as mocked_send:
    from format_email import CarsEmails
    emails = CarsEmails(email_client=MagicMock(), config=config)
    emails.send_cars_email(*test_input)
    mocked_send.assert_called_with(*expected_output)

or reload the module e.g. with importlib.reload():

import importlib

import format_email

with patch('cars.lib.email.send_email') as mocked_send:
    importlib.reload(format_email)
    emails = format_email.CarsEmails(email_client=MagicMock(), config=config)
    emails.send_cars_email(*test_input)
    mocked_send.assert_called_with(*expected_output)

Not that pretty either way, if you ask me. I'd stick with mocking the function in the module where it is called.

๐ŸŒ
Medium
medium.com โ€บ bungalow-garage โ€บ mocking-dependencies-in-a-python-module-6bb82c2c7ce9
Mocking dependencies in a Python module | by Kellen Steffen | Bungalow Garage | Medium
May 21, 2019 - However, mocking a dependency function on an imported module is as simple as providing the path to that function from the reference point of the test file.
Discussions

How to mock individual functions from an imported module with individual return values?
No. In this case you would patch them inside module_to_import, not module_to_test. This is described in the "Where to patch" section of the unittest.mock documentation: However, consider the alternative scenario where instead of from a import SomeClass module b does import a and some_function uses a.SomeClass. Both of these import forms are common. In this case the class we want to patch is being looked up in the module and so we have to patch a.SomeClass instead: More on reddit.com
๐ŸŒ r/learnpython
2
2
May 1, 2023
python - Mocking a module import in pytest - Stack Overflow
I am writing a pytest plugin that should test software that's designed to work inside a set of specific environments. The software I'm writing is run inside a bigger framework, which makes certain Python modules available only when running my Python software inside the framework. In order to test my software, I'm required to "mock" or fake an entire module (actually, quite a few). I'll need to implement its functionality ... More on stackoverflow.com
๐ŸŒ stackoverflow.com
unit testing - Python Mocking a function from an imported module - Stack Overflow
For instance you can use patch as a decorator to mock a value for all tests in an xunit or pytest class while in other cases its useful to have the fine grained control afforded by the context manager. ... The accepted answer is correct that using patch you have to consider the namespace in which it is imported... More on stackoverflow.com
๐ŸŒ stackoverflow.com
python - How to mock a imported object with pytest-mock or magicmock - Stack Overflow
I am trying to understand the mock/monkeypatch/pytest-mock capabilities. Let me know if this is possible. If not could you please suggest how I can test this code. My code structure: / ./app ../ More on stackoverflow.com
๐ŸŒ stackoverflow.com
๐ŸŒ
Uadnan
uadnan.com โ€บ articles โ€บ mocking-imports-in-python-for-unittesting
Mocking Imports in Python for Unit Testing: A Comprehensive Guide | Adnan Umer
April 2, 2023 - This blog post provides a comprehensive guide on how to mock imports in Python for unit testing. It covers the use of sys.modules dictionary and MagicMock objects to replace real modules with mock objects, and provides examples for both pytest and unittest frameworks.
๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ how to mock individual functions from an imported module with individual return values?
r/learnpython on Reddit: How to mock individual functions from an imported module with individual return values?
May 1, 2023 -

I have a file module_to_import.py...

def function_1(foo):
    return 'bar' # actual return value isn't just a constant

def function_2(bar):
    return 'baz' # actual return value isn't just a constant

...and another file module_to_test.py which imports the previous module and calls its functions inside a class...

import module_to_import

class MyClass:

    def method(self):
        foo = ...
        bar = module_to_import.function_1(foo)
        baz = module_to_import.function_2(bar)
        return baz

My goal is to write a test for MyClass.method.

All that method does is call other functions/methods. Those functions/methods already have their own tests. So to test only MyClass.method with no confounding side effects, I'd like to simply mock all the objects that get called inside its body, and test only that those objects are called as expected.

But to do this properly with maximum control, I'll need to mock the return values for each object. Given that the entire module_to_import.py is imported, rather than its functions individually, I'm not quite sure how to do this...

If the functions were imported individually, ...

# module_to_test.py

from module_to_import import function_1, function_2

class MyClass:

    def method(self):
        foo = ...
        bar = function_1(foo)
        baz = function_2(bar)
        return baz

...then it would be as simple as patching them directly from within the namespace of module_to_test...

from unittest.mock import Mock, patch

class TestMyClass:

    def test_method(self):
        mock_function_1_retval = 'bar'
        mock_function_2_retval = 'baz'
        with (
            patch('module_to_test.function_1', return_value=mock_function_1_retval) as mock_function_1,
            patch('module_to_test.function_2', return_value=mock_function_2_retval) as mock_function_2
        ):
            baz = my_class.method()
        mock_function_1.assert_called_once_with('foo')
        mock_function_2.assert_called_once_with('bar')

But as things are, to access function_1 and function_2, I have to do so through their shared namespace module_to_test.module_to_import, e.g.

from unittest.mock import Mock, patch

class TestMyClass:

    def test_method(self):
        with patch('module_to_test.module_to_import') as mock_module_to_import:
            bar = my_class.method()
        # somehow assert `mock_module_to_import.function_1` called with `'foo'`
        # somehow assert `mock_module_to_import.function_2` called with `'bar'`

In that case, I'm unsure how to give the functions different return values.

Can anyone weigh in here? Maybe it's obvious and I'm just approaching this from the wrong angle...

๐ŸŒ
Adam Johnson
adamj.eu โ€บ tech โ€บ 2024 โ€บ 05 โ€บ 17 โ€บ python-mock-inner-import
Python: Mock an inner import - Adam Johnson
May 17, 2024 - import sys from unittest import mock from example import delve def test_delve(): mock_digger = mock.Mock(dig=mock.MagicMock()) with mock.patch.dict(sys.modules, {"digger": mock_digger}): delve() assert mock_digger.dig.mock_calls == [ mock.call(greedily=True, depth=3000), ] MagicMock() is required here because dig() is a function and only MagicMock is callable.
๐ŸŒ
Medium
medium.com โ€บ @zalun โ€บ mocking-the-unmockable-1bf3cc31dad6
Mocking the unmockable. Mocking is often challenging. Here is aโ€ฆ | by Piotr Zalewa | Medium
August 16, 2024 - Weโ€™re seeing the right functions called with the right values on importing the actions module. โžœ mocking_problem > poetry run pytest ============================ test session starts ============================ platform darwin -- Python 3.11.2, pytest-7.2.2, pluggy-1.0.0 rootdir: /Users/zalun/Projects/Medium/mocking_problem, configfile: pytest.ini plugins: dotenv-0.5.2 collected 6 items tests/test_action.py ...
๐ŸŒ
Physics Forums
physicsforums.com โ€บ other sciences โ€บ programming and computer science
Pytest, unittest : Mocking out a non-existent imported module โ€ข Physics Forums
July 9, 2022 - The user demonstrates how to mock ... 'sys.modules'. The solution highlights that when importing a specific function from a module, a full dotted path is unnecessary for mocking....
๐ŸŒ
Chang Hsin Lee
changhsinlee.com โ€บ pytest-mock
pytest: How to mock in Python - Chang Hsin Lee
May 2, 2020 - If you have trouble understanding mocks for testing in Python like me, then this post is for you. ... Both can be installed via pip. ... Hereโ€™s an example. Imagine that you have a function called compute(). Part of its code contains an expensive_api_call() that takes 1,000 seconds to run ยท import time def compute(x): response = expensive_api_call() return response + x def expensive_api_call(): time.sleep(1000) # takes 1,000 seconds return 123
Find elsewhere
๐ŸŒ
pythontutorials
pythontutorials.net โ€บ blog โ€บ mocking-an-imported-function-with-pytest
How to Mock Imported Functions in Pytest: Fixing 'Assertion Not Called' Errors for Email Sending Tests โ€” pythontutorials.net
Because notification.py has already imported send_email into its own namespace. Mocking the original email_sender.send_email doesnโ€™t affect the copy stored in notification.py. Rule of Thumb: Mock the function where it is used, not where it is defined. Pytest simplifies mocking with the pytest-mock plugin, which wraps unittest.mock for cleaner, fixture-based mocking.
Author: microsoft
Top answer
1 of 3
56

pytest provides a fixture for this use-case: monkeypatch.syspath_prepend.

You may prepend a path to sys.path list of import locations. Write a fake fwlib.py and include it in your tests, appending the directory as necessary. Like the other test modules, it needn't be included with the distribution.

After playing with this myself, I couldn't actually figure out how to get the fixture to mock module level imports correctly from the library code. By the time the tests run, the library code was already imported and then it is too late to patch.

However, I can offer a different solution that works: you may inject the name from within conftest.py, which gets imported first. The subsequent import statement within the code under test will just re-use the object already present in sys.modules.

Package structure:

$ tree .
.
โ”œโ”€โ”€ conftest.py
โ”œโ”€โ”€ lib
โ”‚   โ””โ”€โ”€ my_lib.py
โ””โ”€โ”€ tests
    โ””โ”€โ”€ test_my_lib.py

2 directories, 3 files

Contents of files:

# conftest.py
import sys

def fwlib_sum(a, b):
    return a + b

module = type(sys)('fwlib')
module.sum = fwlib_sum
sys.modules['fwlib'] = module

library file:

# lib/my_lib.py
import fwlib

def fw_sum(a, b):
    return fwlib.sum(a, b)

test file:

# lib/test_my_lib.py
import my_lib

def test_sum():
    assert my_lib.fw_sum(1, 2) == 3
2 of 3
10

Just to provide a little more details to @wim's good answer, you can use it with submodules too, like so:

import sys
module = type(sys)("my_module_name")
module.submodule = type(sys)("my_submodule_name")
module.submodule.something = sommething
sys.modules["my_module_name"] = module
sys.modules["my_module_name.my_submodule_name"] = module.submodule
๐ŸŒ
DEV Community
dev.to โ€บ kenakamu โ€บ python-unit-test-with-mock-functions-from-different-modules-cla
python: unit test with mock functions from different modules - DEV Community
March 5, 2023 - This time, I need to create the Mock with a bit more code as I need to mock a function, rather than the simple return_value nor an attribute. from datetime import datetime from unittest.mock import patch, Mock from my_modules.util import add_time @patch('my_modules.util.datetime', Mock(**{"now.return_value": datetime(2023, 1, 1)})) def test_add_time(): expected = f'{datetime(2023, 1, 1)}: input' input = 'input' input = add_time(input) assert expected == input
๐ŸŒ
Greg Reda
gregreda.com โ€บ 2021 โ€บ 06 โ€บ 28 โ€บ mocking-imported-module-function-python
Mocking an imported module-level function in Python
June 28, 2021 - from other_module.thing import Thing thing = Thing() with patch.object('other_module.fetch_thing') as mocked: mocked.side_effect = Exception('mocked error') data = thing.run() Note the very subtle difference in the string path we are passing to patch.object. Because we are importing the function into other_module where our class uses it, that is what we need to mock.
๐ŸŒ
pytest
docs.pytest.org โ€บ en โ€บ 7.1.x โ€บ how-to โ€บ monkeypatch.html
How to monkeypatch/mock modules and environments โ€” pytest documentation
Sometimes tests need to invoke functionality which depends on global settings or which invokes code which cannot be easily tested such as network access. The monkeypatch fixture helps you to safely set/delete an attribute, dictionary item or environment variable, or to modify sys.path for importing. The monkeypatch fixture provides these helper methods for safely patching and mocking functionality in tests:
Top answer
1 of 4
5

I believe you are right not testing cases on a real database because it's not unit testing anymore if you are using external dependencies.

There is a possibility to specify return-value and customize it (different return values on each iteration even) for Mock or MagicMock objects.

from unittest.mock import Mock, patch 

from app import db_conn


@patch('app.db_conn.find')
def test_some_func1(db_con_mock):
    ...
    assert ...

Keep in mind that in each patch you should specify the import path of db_conn - the path where db_conn **is used (I assume it's a different path in each test), not where it is defined.

2 of 4
3

To answer the intial question "How to mock a imported object with pytest-mock or magicmock" you can do:

from unittest import mock  # because unittest's mock works great with pytest

def test_some_func1():
    with mock.patch('some_module1.db', mock.MagicMock(return_value=...)) as magicmock:
        result = some_func1(...)
        assert ... e.g. different fields of magicmock
        assert expected == result

# or alternatively use annotations

@mock.patch('some_module2.db', mock.MagicMock(return_value=...))
def test_some_func2():
        result = some_func2(...)

note that you do not patch the actual source of db

For your other use case

I want to mock the database (using a mongo database), more specifically the "db_conn" object

you similarly follow the hints of the link above:

mock.patch('some_module1.db_conn', mock.MagicMock(return_value=...))

Given that, you will notice in your tests that db from `db = db_conn.db_name2.db_collection2' will create another mock object. Calls to that object will be recorded as well. In such a way you will be able to trace history of calls and values assignments as well.


Furthermore, see an example how to pach mongo db.

For testing of Flask apps see the documentation of flask. Also this is a nice explanation as well, and uses DB connections.

As a general hint, like @MikeMajara mentioned - separate your code more into smaller functions that are also easy to test. In tradition to TDD: write tests first, implement later, and refactor (especially DRY!)

๐ŸŒ
Reddit
reddit.com โ€บ r/learnpython โ€บ mocking functions from an imported class.
r/learnpython on Reddit: Mocking functions from an imported class.
September 1, 2023 -

So, in my application I've got something like:

application.py

from module import x
....
class Zzz:
......
 def class_function():.

      instance = x.Yyyy(param1, param2)

      results = instance.function_to_be_mocked(p1,p2)

I've tried several different ways of mocking the function, but I always get some variation on "type object '??' has no attribute '??' depending on what path I try to use to mock it.

with patch.object(_path-to-class_, 'function-to-be-mocked) as mocked-fn: always gives errors no matter what path I use.

If my test class has it's own instance of Zzz, what is the right way to patch "function_to_be_mocked"?

for the path to the class i've tried:

Zzz.module.x.Yyyy - got "Zzz has no attribute module"

Zzz.x.Yyyy - got "Zzz has no attribute x"

self.test_instance_zzz.Yyyy - got "Zzz has no attribute Yyyy"

and probably a couple of others i've forgotten.

๐ŸŒ
sqlpey
sqlpey.com โ€บ python โ€บ solved-top-4-ways-to-mock-a-function-in-python
Solved: Top 4 Ways to Mock a Function from an Imported Module in Python
November 1, 2024 - A: You can use the monkeypatch feature in pytest or the patch decorator from the unittest.mock module to mock global functions.