PyTest : dynamically generating test name during runtime
Asked Answered
D

2

6

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.

Dmitri answered 20/4, 2020 at 8:10 Comment(1)
You cannot do this. All you can is to set custom name for every option in parametrize values by setting ids arguments. Take a look at docs.pytest.org/en/latest/example/… (test test_timedistance_v1). You can customize the value displayed in square brackets during test run.Hawthorn
F
9

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.

Fultz answered 20/4, 2020 at 17:10 Comment(3)
Thanks will try that and will let you knowDmitri
Great it worked , but now i want to add another layer of complexity. Let's say that : ``` values_list=[{'apple':'5'},{'tomatoes':'1'},{'potatoes': '32}] ``` I want the name of the test to be test_5, test_1 and so on , is there a way to access those values ? I've tried doing that via the setup_method in the test class itself, but i cant access the dictionary from there (even in debug).Dmitri
Thanks in advance but i managed to figure it out , it took some digging but eventually i've discovered it was sitting in a nsested structure inside : iitem.own_markers[0].args[1] So i did some maniuplation with that data and managed to extract the required fieldDmitri
C
0

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'))
Caz answered 14/8 at 14:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.