pythonunit-testingmockingpytestpytest-mock

pytest mock failing when mocking function from imported package


pytest-mock is properly installed:

> pip list | grep pytest
pytest                7.4.2
pytest-mock           3.14.0

This unit test passes with success:

import pytest

class A:
    def __init__(self, value):
        self.value = value

def get_a() -> A:
    return A(1)

@pytest.fixture
def mocked_A(mocker):
    a = A(2)
    mocker.patch(f"{__name__}.get_a", return_value=a)

def test_mocked_a(mocked_A) -> None:
    a = get_a()
    assert a.value == 2

Now, if I move A and get_A to mypackage.mymodule, mocking stops to work.

import pytest

# note: these imports work: mypackage is correctly installed
from mypackage.mymodule import A, get_a

@pytest.fixture
def mocked_A(mocker):
    a = A(2)
    mocker.patch("mypackage.mymodule.get_a", return_value=a)

def test_mocked_a(mocked_A) -> None:
    a = get_a()
    assert a.value == 2

The test fails with this error:

mocked_A = None

    def test_mocked_a(mocked_A) -> None:
        a = get_a()
>       assert a.value == 2
E       assert 1 == 2
E        +  where 1 = <mypackage.mymodule.A object at 0x7f063e3f2c80>.value

test_a.py:13: AssertionError
=============================================================================== short test summary info ================================================================================
FAILED test_a.py::test_mocked_a - assert 1 == 2

Looks like get_a has not been mocked. Anything I am doing wrong ?


Solution

  • Unlike imported modules/packages get_a is an ordinary identifier that points to the function that you want to patch without looking it up in mypackage.mymodule, as this is already done during the import. So in this case you have to patch it directly via f"{__name__}.get_a" like in your first test. This is not a special behavior of pytest-mock.