Search code examples
pythonpython-3.xpytestparameterized-unit-test

Customizing pytest parameterized test name


I've the following tests:

@pytest.mark.parametrize(
    "nums",
    [[3, 1, 5, 4, 2], [2, 6, 4, 3, 1, 5], [1, 5, 6, 4, 3, 2]]
)
def test_cyclic_sort(nums):
    pass


@pytest.mark.parametrize(
    "nums, missing",
    [([4, 0, 3, 1], 2)]
)
def test_find_missing_number(nums, missing):
    pass

I'd like to customize the test names to include the input array. I've read the pytest docs, and this question and this question, but none answer the following questions:

  1. What is passed to the id func? In my code above, the first test takes one parameter, the second takes two.
  2. pytest docs use a top-level function for id, whereas I'd like to put my tests in a class and use a @staticmethod. Trying to reference the static method with TestClass.static_method from inside TestClass gives an error in PyCharm; what is the correct syntax for doing this?

Edit: Created https://github.com/pytest-dev/pytest/issues/8448.


Solution

  • When using a callable for the ids keyword, it will be called with a single argument: the value of the test parameter being parametrized. The callable ids return a string, which will be used in square brackets as the test name suffix.

    If the test is parametrizing over multiple values, the function will still be called with a single argument, but it will be called multiple times per test. The generated name will be joined with dashes, something like

    "-".join([idfunc(val) for val in parameters])
    

    For example:

    test_something[val1-val2-val3]
    

    Here is the join in the pytest source.

    To use a static method, this syntax works:

    class TestExample:
    
        @staticmethod
        def idfunc(val):
            return f"foo{val}"
    
        @pytest.mark.parametrize(
            "x, y",
            [
                [1, 2],
                ["a", "b"],
            ],
            ids=idfunc.__func__,
        )
        def test_vals(self, x, y):
            assert x
            assert y
    

    This will generate two tests, calling idfunc four times as described above.

    TestExample::test_vals[foo1-foo2]
    TestExample::test_vals[fooa-foob]