Search code examples
python-3.xpytest

Maintaining and reporting a variable across multiple test


How can we maintain a variable across multiple tests and report this ( either to console or in a file)?

Assuming you have a function in a module called math_operations.py that calculates the sum of two numbers:

# math_operations.py

def add_numbers(a, b):
    return a + b

Let us create a Pytest test module named test_math_operations.py with two tests. I would like to to maintain the total score across both tests:

# test_math_operations.py
import pytest
from math_operations import add_numbers

@pytest.fixture
def score():
    return {"score_pos": 0, "score_neg": 0}

def test_add_numbers_positive(score):
    result = add_numbers(2, 3)
    assert result == 5
    score["score_pos"] =2
    assert score["score_pos"] == 2


def test_add_numbers_negative(score):
    result = add_numbers(-5, 10)
    assert result == 5
    score["score_neg"] = 3
    assert score["score_neg"] == 3

#print(score)

Updated test_math_operations.py after the comment received by @R.K (below)

# test_math_operations.py
import pytest
from math_operations import add_numbers

class DemoClass:
  score_pos = 0
  score_neg = 0

@pytest.fixture() # (score="class")
def score():
  test = DemoClass
  yield test

scoreClass = DemoClass()

class TestDemo:
    global scoreClass
    def test_add_numbers_positive(score):
        result = add_numbers(2, 3)
        assert result == 5
        scoreClass.score_pos =2

    def test_add_numbers_negative(score):
        result = add_numbers(-5, 10)
        assert result == 5
        scoreClass.score_neg = 3

print(scoreClass.score_neg, scoreClass.score_neg)

I would like to have the total value of the score, if I cannot get pytest to output the score dictionary to me.

Any help would be greatly appreciated.


Solution

  • One way to approach this is to use a fixture with scope=module:

    # test_math_operations.py
    import pytest
    from math_operations import add_numbers
    
    
    @pytest.fixture(scope="module")
    def score():
        the_score = {"score_pos": 0, "score_neg": 0}
        yield the_score
        print(f"\nSUMMARY\n{the_score=}")
    
    
    def test_add_numbers_positive(score):
        result = add_numbers(2, 3)
        assert result == 5
        score["score_pos"] = 2
        assert score["score_pos"] == 2
    
    
    def test_add_numbers_negative(score):
        result = add_numbers(-5, 10)
        assert result == 5
        score["score_neg"] = 3
        assert score["score_neg"] == 3
    

    Output:

    $ pytest -v -s
    
    test_math_operations.py::test_add_numbers_positive PASSED
    test_math_operations.py::test_add_numbers_negative PASSED
    SUMMARY
    the_score={'score_pos': 2, 'score_neg': 3}
    

    Notes

    • I use the module scope to ensure that there is only one dictionary per module
    • Instead of return, I yield, then after yield, I can print the summary
    • When invoking pytest, I use the -s option to show the output of the print function