Bored002
Bored002

Reputation: 403

PyTest : dynamically generating test name during runtime

I want to name the test dynamically during run-time when i run them with the @pytest.mark.parametrize("value",values_list) fixture. for example:

values_list=['apple','tomatoes','potatoes']

@pytest.mark.parametrize("value",values_list)
def test_xxx(self,value):
    assert value==value

the final outcome i want to see is 3 tests with the following names:

test_apple

test_tomatoes

test_potatoes

i gave tried looking in to pytest documentation but i haven found anything that might shed light on this problem.

Upvotes: 6

Views: 4972

Answers (2)

nismotri
nismotri

Reputation: 97

When working with parametrized tests in pytest, I usually have a method for getting data from the test parameters file, e.g. like this:

def get_data(file_name='test_parameters.json'):
    
    test_file_dir = os.path.dirname(os.path.abspath(__file__))
    file_path = os.path.join(test_file_dir, file_name)
    
    # Read the JSON file
    with open(file_path, 'r') as f:
        data = json.load(f)
    
    return data

Then I use this mark passing parameters to the parametrized test:

@pytest.mark.parametrize("values", get_data())

So, in order to add the ids to the tests I just add another parameter to the method:

def get_data(file_name='test_parameters.json', return_data = 'all'):

    test_file_dir = os.path.dirname(os.path.abspath(__file__))
    file_path = os.path.join(test_file_dir, file_name)
    
    with open(file_path, 'r') as f:
        data = json.load(f)

    if return_data == 'test_names':
        return [item['test_name'] for item in data]
    else:
        return data

and update the mark like this:

@pytest.mark.parametrize("values", get_data(), ids=get_data(return_data='test_names'))

Upvotes: 0

hoefling
hoefling

Reputation: 66231

You can change the names displayed in test execution by rewriting the _nodeid attibute of the test item. Example: create a file named conftest.py in your project/test root dir with the following contents:

def pytest_collection_modifyitems(items):
    for item in items:
        # check that we are altering a test named `test_xxx`
        # and it accepts the `value` arg
        if item.originalname == 'test_xxx' and 'value' in item.fixturenames:
            item._nodeid = item.nodeid.replace(']', '').replace('xxx[', '')

Running your tests will now yield

test_fruits.py::test_apple PASSED
test_fruits.py::test_tomatoes PASSED
test_fruits.py::test_potatoes PASSED

Beware that overwriting _nodeid should be enjoyed with caution as each nodeid should remain unique. Otherwise, pytest will silently drop executing some tests and it will be hard to find out why.

Upvotes: 9

Related Questions