Gerry
Gerry

Reputation: 2140

pytest fake filesystem and unittest mock interfere

I have a large pytest suite for a django project which uses plenty of mockers (unittest.mock, requests-mock and aioresponses) and a fake filesystem. I have set up the fake filesystem to use some directories which are required by django:

PROJECT_BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
fs.add_real_paths(
    [
        PROJECT_BASE_DIR,
        os.path.dirname(django.__file__),
    ]
)

At random, mockers stop working. AssertionError: Expected 'some_mocked_method' to be called once. Called 0 times. I recieve no other errors or warnings, just the above message. I cannot reproduce this in a minimal example, since it only occurrs on some executions, not every time. When it happens, the tests freeze and I cannot even wait for the test suite to finish. I run them in parallel with pytest-xdist and 8 workers, which might also play a part in the problem. (see EDIT)

I do not even know where to start on this problem. Has anyone experienced something similar when using the combination betweek unittest.mock and pyfakefs? Is there any alternative to pyfakefs? I could not find anything similar. Is there any reason why these two would even interfere?

Here are the package versions I'm using

pyfakefs==5.3.2
pytest==7.4.3
pytest-django==4.7.0
pytest-mock==3.12.0
pytest-xdist==3.5.0

EDIT

Finally, I did produce a minimal example: https://github.com/konnerthg/minimal_django_pyfakefs_unittest_mock

Am I missing something very simple and obvious? Or is this a bug?

EDIT 2

Here's the output after running pytest in the project linked above. After pytest -m without_fakefs (this is a dummy test case which checks that the pytest setup is correct): 2 passed, as expected.

But after running pytest -m with_fakefs, i.e. the exact same test case, but with the fs fixture, I receive:

___________________________________________________ test_fs_and_mocker[1] ____________________________________________________

client = <django.test.client.Client object at 0x7f1e94f7a850>
fs = <pyfakefs.fake_filesystem.FakeFilesystem object at 0x7f1e94f7bb90>, counter = 1

    @pytest.mark.with_fakefs
    @pytest.mark.parametrize("counter", range(2))
    def test_fs_and_mocker(
        client,
        fs,
        counter,
    ):
        with unittest.mock.patch("mysite.views.foo") as mocker:
            client.get("/foo/")
>           mocker.assert_called()

.../minimal_django_pyfakefs_unittest_mock/mysite/tests/mysite/views_test.py:14: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <MagicMock name='foo' id='139769325143440'>

    def assert_called(self):
        """assert that the mock was called at least once
        """
        if self.call_count == 0:
            msg = ("Expected '%s' to have been called." %
                   (self._mock_name or 'mock'))
>           raise AssertionError(msg)
E           AssertionError: Expected 'foo' to have been called.

/usr/lib/python3.11/unittest/mock.py:908: AssertionError

================================================== short test summary info ===================================================
FAILED tests/mysite/views_test.py::test_fs_and_mocker[1] - AssertionError: Expected 'foo' to have been called.
=================================== 1 failed, 1 passed, 2 deselected, 2 warnings in 0.25s ====================================

Note that the first case (i.e. the first execution of the same test) always succeeds. If I run it 10 times rather than 2, the first succeeds and the other 9 fail. Moreover, if I run the cases in parallel with xdist and 8 workers, the first 8 succeed and everything thereafter fails.

I run Ubuntu 23.04, 64-bit, Kernel Version Linux 6.2.0-36-generic on a Lenovo IdeaPad 5 Pro 16ARH7 with an AMD Ryzen™ 7 6800HS Creator Edition × 16 processor. Python 3.11.4

Upvotes: 0

Views: 210

Answers (0)

Related Questions