pythonpytestpython-import

pytest independent import of the same module from different test files


The following subject module contains two functions, one of which manipulates a global variable.

mod.py:

def global_setter():
    global x
    x = 123
    print("setter x:", x)


def global_getter():
    print("getter x:", x)

For each function there is a test file.

test_1.py

import pytest

import mod


def test_set_x():
    mod.global_setter()
    assert mod.x == 123

test_2.py

import pytest

import mod


def test_get_x():
    with pytest.raises(NameError):
        mod.global_getter()

These tests pass if run separately

$ pytest -s -v test_1.py
========================== test session starts ==========================
platform linux -- Python 3.6.7, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /mnt/temp/test, inifile:
collected 1 item

test_1.py::test_set_x setter x: 123
PASSED

-

======================= 1 passed in 0.03 seconds ========================
$ pytest -s -v test_2.py
========================== test session starts ==========================
platform linux -- Python 3.6.7, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /mnt/temp/test, inifile:
collected 1 item

test_2.py::test_get_x PASSED

======================= 1 passed in 0.02 seconds ========================

If run together, the second test fails.

$ pytest -s -v test_1.py test_2.py
========================== test session starts ==========================
platform linux -- Python 3.6.7, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /mnt/temp/test, inifile:
collected 2 items

test_1.py::test_set_x setter x: 123
PASSED
test_2.py::test_get_x getter x: 123
FAILED

=============================== FAILURES ================================
______________________________ test_get_x _______________________________

    def test_get_x():
        with pytest.raises(NameError):
>           mod.global_getter()
E           Failed: DID NOT RAISE <class 'NameError'>

test_2.py:8: Failed
================== 1 failed, 1 passed in 0.08 seconds ===================

It seems that the state of the imported module bleeds between tests and test files.

Why does this happen, and is there a way to tell pytest to import modules independently for each test file? If so, what would be a way to accomplish it with minimal changes to the test_ functions? The above toy example illustrates a problem that I have with a larger code base with many tests.


Solution

  • This is expected because all the tests run via pytest are run in a single process and your first test is mutating the global state by adding x to the global namespace.

    You have a couple of options.

    1. Refactor your code to not use global variables. Or at the very least, encapsulate it within a class which makes it easy to mock.
    2. Use a framework like pytest-xdist (see Run py.test test in different process) which ensures your tests are run in different processes .
    3. Add a fixture before your second test, which explicitly unsets the global variable x.