Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access parametrize parameter from other decorator

Tags:

python

pytest

I am writing a PyTest plugin in which I implemented different custom markers using this function:

def pytest_configure(config):
    config.addinivalue_line("markers", "title(a_title): a title to present the test case")

These markers are then used to add custom properties for each test case in the jUnit output.

Now, since I find myself using very often the parametrize marker, I would like to fill part of my marker with the value of an argument defined in the parametrize marker.

Here is an example of what I am trying to accomplish. The code is the following:

class TestClass:
    @pytest.mark.parametrize("param", ["value1", "value2"])
    @pytest.mark.title(f"This test case checks that param is {param}")
    def test_simple_test_case(self, param):
        pass

I would like the XML output to be filled like this:

<testcase classname="test_example.TestClass" name="test_simple_test_case[value1]" time="0.001">
    <properties>
        <property name="title" value="This test case checks that param is value1"/>
    </properties>
</testcase>
<testcase classname="test_example.TestClass" name="test_simple_test_case[value2]" time="0.001">
    <properties>
        <property name="title" value="This test case checks that param is value2"/>
    </properties>
</testcase>
<testcase classname="test_example.TestClass" name="test_simple_test_case[value3]" time="0.001">
    <properties>
        <property name="title" value="This test case checks that param is value3"/>
    </properties>
</testcase>

Everything is working except passing the parametrize argument to my custom marker (title).

like image 938
dariofac Avatar asked Jul 02 '21 15:07

dariofac


1 Answers

You can access parametrize parameters in item.callspec.params.

def pytest_collection_modifyitems(session, config, items):
    for item in items:
        for marker in item.iter_markers(name="title"):
            # title = marker.args[0]                               # Change this
            title = marker.args[0].format(**item.callspec.params)  # to this
            item.user_properties.append(("title", title))

Usage:

class TestClass:
    @pytest.mark.parametrize("param", ["value1", "value2"])
    # @pytest.mark.title(f"This test case checks that param is {param}")  # Change this
    @pytest.mark.title("This test case checks that param is {param}")     # to this
    def test_simple_test_case(self, param):
        pass

To handle the case where parametrize is not used, or some format strings are not specified:

class SafeDict(dict):
    def __missing__(self, key):
        return "{" + key + "}"


def pytest_collection_modifyitems(session, config, items):
    for item in items:
        for marker in item.iter_markers(name="title"):
            title = marker.args[0]
            if hasattr(item, "callspec"):
                title = title.format_map(SafeDict(item.callspec.params))
            item.user_properties.append(("title", title))

Reference: https://stackoverflow.com/questions/17215400/format-string-unused-named-arguments/17215533#17215533

like image 58
aaron Avatar answered Sep 24 '22 08:09

aaron