简体   繁体   中英

Pytest parametrize test case share a class variable

I have recently started using pytest and I have written a following class.

import pytest
import yaml
import random

testcases = list()
class TestSample(object):
    test_yml_file = "/tmp/test_inputs.yml"

    yamlTestList = list()
    with open(test_yml_file, 'r') as testYamlFile:
        yamlTestList = yaml.load(testYamlFile)

    global testcases
    testcases = []

    for d in yamlTestList['testcases']:
        temp = dict()
        for k,v in d.items():
            temp[k] = v
        testcases.append((temp['testcase'],temp))

    last_value = 2

    @classmethod
    def setup_class(self):
        test_sample = TestSample()

    @pytest.mark.debug
    @pytest.mark.parametrize(('testname', 'testInput'), testcases)
    def test_run(self,testname,testInput):
        if last_value >= 10:
            last_value += random.randint(1,10)

Current issue is - For each parameterize test, last_value is set to 2 always. How can we use value of 'last_value' variable changed in previous test case into the current test case?

Answer:

You will need to instantiate the lastvalue variable in an outer scope, from which the parameterized function can be called, and not in the test class itself. This is because of how the parameterization works with pytest. Each function call with each individual parameter set exists in a separate scope, so in your code you are basically resetting the lastvalue variable to 2 each time before calling the function.

Solution 1:

I don't recommend globals, but following your example, this demonstrates what I am talking about.


last_value = 0


class TestSample(object):
    testcases = [("name1", 1), ("name2", 2), ("name3", 3), ("name4", 4)]

    @pytest.mark.parametrize(('testname', 'testInput'), testcases)
    def test_run(self, testname, testInput):
        global last_value
        if last_value >= 10:
            last_value += random.randint(1, 10)
        else:
            last_value += 5

        print(last_value)

Note also that I added an else clause to the function to test this with. Even if the parameterization worked similar to a loop within a single class instance, the lastvalue variable would have never changed anyways in your example code as the if last_value >= 10 clause never has a chance to be met and thus the lastvalue increment never actually occurs.

Best Solution:

Instead of using globals I would recommend using a pytest fixture with a "class" scope. You can read about fixtures and fixture scopes in the pytest docs here.

@pytest.fixture(name="sample_manager", scope="class")
def sample_manager_fixture():
    class SampleManager:
        def __init__(self):
            self.last_value = 0

    return SampleManager()


class TestSample:
    testcases = [("name1", 1), ("name2", 2), ("name3", 3), ("name4", 4)]

    def test_order(self, sample_manager):
        print(sample_manager.last_value)

    @pytest.mark.parametrize(('testname', 'testInput'), testcases)
    def test_run(self, testname, testInput, sample_manager):
        if sample_manager.last_value >= 10:
            sample_manager.last_value += random.randint(1, 10)
        else:
            sample_manager.last_value += 5

        print(sample_manager.last_value)

The sample_manager_fixture() fixture function returns a SampleManager class instance when it is passed to a test function. Pytest handles all of this behind the scenes, so all you need to do is include the fixture name (declared explicitly in my case) as a parameter. The fixture scope defines the "lifespan" of each particular object instance returned from the fixture. So, setting the scope to "class" for the fixture notifies pytest that you want all test functions in a particular class to share the same instance of the object returned from the fixture. You can return any object, with any structure, from fixtures that you want, so they are a really powerful tool to manage data across your tests.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM