surabhi
surabhi

Reputation: 29

How to avoid calling pytest_generate_tests multiple times

I have a test suite, wherein

My problem is:

Parent Class :

class Regression:
    def test_work(self, data):
        test_func1_call_using data(data)
    
    def test_agg(self, data):
        test_func2_call_using data(data)

Test Class 1 inherting regression :

@pytest.mark.usefixtures('generic_test_setup')
class Test_window(Regression):
   dummy_var=0

Test Class 2 inherting regression :

@pytest.mark.usefixtures('generic_test_setup')
class Test_door(Regression):
   dummy_var=0    

conftest.py :

@pytest.fixture(scope="class")
def generic_test_setup(request, env):
   # do setup 

def pytest_generate_tests(metafunc):
    class_name = metafunc.cls.__name__.split('_')[1]
    
    logging.info(f"Collection Phase :: Initializing test_data for {class_name} !!!")
    
    # Initialize the test data based on the calling class 
    test_data = # generated dictionary value with ids and test data

    id_entity = [d['entity'] for d in test_data]
    if "data" in metafunc.fixturenames:
        metafunc.parametrize("data", test_data, ids=id_entity )
        
@pytest.fixture
def data(request):
    return request.param

Upvotes: 0

Views: 1309

Answers (1)

MrBean Bremen
MrBean Bremen

Reputation: 16815

As mentioned in the comments, the behavior of pytest_generate_tests is as expected, as it is called for each test. If you want to cache your test data, you can just add a cache outside of the hook, e.g. something like:

testdata_cache = {}

def pytest_generate_tests(metafunc):
    if "data" in metafunc.fixturenames:
        class_name = metafunc.cls.__name__.split('_')[1]
        if class_name not in testdata_cache:
           # Initialize the test data based on the calling class
           testdata_cache[class_name] = # generated dictionary value with ids and test data
        test_data = testdata_cache[class_name]

        id_entity = [d['entity'] for d in test_data]
        metafunc.parametrize("data", test_data, ids=id_entity )

If you don't want to use a global variable, you could wrap this into a class, but this would be overkill in this case.

Upvotes: 2

Related Questions