Coding thermodynamist
Coding thermodynamist

Reputation: 1403

Legacy code: how to test values of global variables with pytest

DISCLAIMER: This question is only about testing global variables in a existing code base (legacy code). Do not use global variables for new code, as (among many other reasons) it makes it more difficult to test

I am dealing with some legacy code that relies a lot on global variables.

This legacy code has a main function that are calling other functions, those nested functions changing the values of the global.

I want to refactor all of that by starting to put a test on the main calling function and refactoring the nested ones. To do so, I want to check the values of the global variables after the call to the main function.

However, I cannot make it work in pytest, here are my two attempts:

Attempt

Folder structure:

legacy_code.py:

GLOBAL_LIST = None


def add_to_global_list(data: str):
    global GLOBAL_LIST
    if GLOBAL_LIST is None:
        GLOBAL_LIST = [data]
    else:
        GLOBAL_LIST.append(data)

conftest.py:

import pytest

from src.legacy_code import GLOBAL_LIST


@pytest.fixture(scope="function")
def GLOBAL_VAR():
    yield GLOBAL_LIST

test_legacy_code_attempt1.py:

from src.legacy_code import add_to_global_list, GLOBAL_LIST


def test_global_list():
    # global GLOBAL_LIST # I tried with or without this line, the result is the same
    assert GLOBAL_LIST is None

    add_to_global_list("one input")

    assert len(GLOBAL_LIST) == 1

test_legacy_code_attempt2.py:

from src.legacy_code import add_to_global_list


def test_global_list(GLOBAL_VAR):

    assert GLOBAL_VAR is None

    add_to_global_list("one input")

    assert len(GLOBAL_VAR) == 1

However, when I run that with python -m pytest I get :

    def test_global_list():

        assert GLOBAL_LIST is None

        add_to_global_list("one input")

>       assert len(GLOBAL_LIST) == 1
E       TypeError: object of type 'NoneType' has no len()

tests\test_legacy_code_attempt1.py:10: TypeError
GLOBAL_VAR = None

    def test_global_list(GLOBAL_VAR):

        assert GLOBAL_VAR is None

        add_to_global_list("one input")

>       assert len(GLOBAL_VAR) == 1
E       TypeError: object of type 'NoneType' has no len()

tests\test_legacy_code_attempt2.py:10: TypeError
FAILED tests/test_legacy_code_attempt1.py::test_global_list - TypeError: object of type 'NoneType' has no len()
FAILED tests/test_legacy_code_attempt2.py::test_global_list - TypeError: object of type 'NoneType' has no len()

As you see, the global variable is actually never changed and I would expect these tests to pass

I am using python 3.9.5 and pytest 6.2.4.

Upvotes: 1

Views: 417

Answers (1)

quamrana
quamrana

Reputation: 39414

You cannot import variables like that because you lose the reference to them when they are assigned to. You meant to do this:

from src import legacy_code


def test_global_list():
    
    assert legacy_code.GLOBAL_LIST is None
    ...
    # use legacy_code.GLOBAL_LIST wherever you need to

Upvotes: 1

Related Questions