user1179317
user1179317

Reputation: 2913

Pytest: Patch a global variable

How do you patch a variable with mock or pytest-mock. Assume the variable is defined in another python script and is used by many other scripts. I would like to mock it within pytest_cmdline_main so that all the scripts using that variable will be mocked accordingly.

A quick example will be

in env.py

VAR = "something"

in conftest.py

import os
import sys
from unittest.mock import patch


TEST_DIR = os.path.dirname(os.path.realpath(__file__))


class MockThings():
    def __init__(self):
        self.setup()

    def setup(self):
        mock_var = patch('env.VAR').start()
        mock_var.return_value = "updated"


def pytest_cmdline_main(config):
    sys.path.append(TEST_DIR)
    MockThings()

in test_something.py

from env import VAR


def test_sample():
    print(VAR)
    # do something else here
    assert False
    
def test_sample2():
    print(VAR)
    # do something else here
    assert False

When you run pytest -v

The test will fail as expected, but under the stdout it will state something like: <MagicMock name='VAR' id='140102687826416'>

Because it is treating the mock as a function, if I replace the print(VAR) with print(VAR()) then the print out will be correct (updated).

How do I mock this variable, and not treat it as a function? I know you can just set VAR="updated" in the test function itself, but I just want it mocked and I guess this is not a great representation of my actual use case, but I just wanted to have a quick simple test code you can run and understand easily.

Upvotes: 3

Views: 9282

Answers (1)

Laurent
Laurent

Reputation: 13488

Suppose you have env.py like this:

VAR = "something"

def func():
    return VAR

Then, in test_something.py, you could mock VAR like this:

import pytest

from env.py import func


@pytest.fixture
def var(mocker):
    return mocker.patch("env.VAR", new="updated", autospec=False)


def test_func(var):
    print(func())
    assert func() == "updated"

In which case, running pytest . -v -s will print out:

test_something.py::test_func updated
PASSED

Upvotes: 0

Related Questions