Skip to content

Keyword-based parameter sets #9216

@ikonst

Description

@ikonst

In many of my tests I've been using pytest.param(..., id="...") as means of providing more readable identifiers for my tests inline, since otherwise with multiple parameters, the autogenerated id is hard to read.

Some of my parameter-driven tests end up growing beyond 2-3 arguments and maintaining the parameters positionally becomes error-prone and hurts readability. The reader has to mentally "zip" a list of parameters (of a parameter set) to the parameter names defined earlier, and if you need to add a parameter, now you need to add them to each and every test, and if you want to insert it (e.g. to maintain grouping), you'd have to carefully count parameters in each of the sets.

One pattern I've been introducing in such cases is defining a "ParamSet" attrs base class:

import attr


@attr.s(auto_attribs=True, kw_only=True)
class ParamSet:
    """
    Use as base class for sets for parameters for @pytest.mark.parametrize
    when you find yourself passing too many parameters positionally.
    """

    id: str

    @property
    def __name__(self) -> str:  # indicate the id to pytest
        return self.id

From there, a test would look like:

@attr.s(auto_attribs=True, kw_only=True)
class MyComplexTestParamSet(ParamSet):
   foo: int
   bar: str = 'some_default'
   expected_baz: float


@pytest.mark.parameterize('params', [
   MyComplexTestParamSet(foo=42, expected_baz=42.42, id="happy path"),
   ...
])
def test_complex(params: MyComplexTestParamSet):
   ...

Before we discuss specifics, is this something we'd want pytest.param to enable?

To give an idea, I'd imagine usage like:

@pytest.mark.parameterize('params', [
   pytest.param(foo=42, expected_baz=42.42, id="happy path"),
   ...
])
def test_complex(params: Any):
   ...

or something more typed like this: (I like the fact that the type hint enables better developer experience when working on the test)

class MyComplexTestParamSet(pytest.ParameterSet):
  foo: int
  ...

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: parametrizerelated to @pytest.mark.parametrizetype: proposalproposal for a new feature, often to gather opinions or design the API around the new feature

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions