Implement unpacking nested pytest.param objects
- Merge nested ids (if parent pytest.param don't have id) - Merge nested marks with parent
This commit is contained in:
parent
1824349f74
commit
ebfdb5fe28
1
AUTHORS
1
AUTHORS
|
@ -334,6 +334,7 @@ Virgil Dupras
|
|||
Vitaly Lashmanov
|
||||
Vlad Dragos
|
||||
Vlad Radziuk
|
||||
Vladimir Gorkavenko
|
||||
Vladyslav Rachek
|
||||
Volodymyr Piskun
|
||||
Wei Lin
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
Now ``pytest`` do unpack nested ``pytest.param`` values and merge their ids and marks.
|
||||
If parent ``pytest.param`` has an id - it rewrites nested ids.
|
||||
For example, now such a construction is possible::
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"a,b,c", [
|
||||
pytest.param(
|
||||
pytest.param(1, id="one", marks=pytest.mark.one),
|
||||
pytest.param(2, id="two", marks=pytest.mark.two),
|
||||
pytest.param(3, id="three", marks=pytest.mark.three),
|
||||
marks=pytest.mark.full
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
Earlier in this case the values ``a, b, c`` in test are a ``ParameterSet`` objects
|
|
@ -1126,9 +1126,21 @@ class Metafunc:
|
|||
# Create the new calls: if we are parametrize() multiple times (by applying the decorator
|
||||
# more than once) then we accumulate those calls generating the cartesian product
|
||||
# of all calls.
|
||||
# If we parametrize the test using values that contained nested pytest.param objects,
|
||||
# then we unpack them values and merge marks.
|
||||
newcalls = []
|
||||
for callspec in self._calls or [CallSpec2()]:
|
||||
for param_index, (param_id, param_set) in enumerate(zip(ids, parameters)):
|
||||
normalized_values = []
|
||||
merged_marks = list(param_set.marks) if param_set.marks else []
|
||||
for param_value in param_set.values:
|
||||
if not isinstance(param_value, ParameterSet):
|
||||
normalized_values.append(param_value)
|
||||
else:
|
||||
normalized_values.append(*param_value.values)
|
||||
if param_value.marks:
|
||||
merged_marks.append(*param_value.marks)
|
||||
param_set = ParameterSet(values=tuple(normalized_values), marks=merged_marks, id=None)
|
||||
newcallspec = callspec.setmulti(
|
||||
valtypes=arg_values_types,
|
||||
argnames=argnames,
|
||||
|
@ -1385,10 +1397,15 @@ def _idvalset(
|
|||
return parameterset.id
|
||||
id = None if ids is None or idx >= len(ids) else ids[idx]
|
||||
if id is None:
|
||||
this_id = [
|
||||
_idval(val, argname, idx, idfn, nodeid=nodeid, config=config)
|
||||
for val, argname in zip(parameterset.values, argnames)
|
||||
]
|
||||
this_id = []
|
||||
for val, argname in zip(parameterset.values, argnames):
|
||||
to_get_idval = val
|
||||
if isinstance(val, ParameterSet):
|
||||
if val.id:
|
||||
this_id.append(val.id)
|
||||
continue
|
||||
to_get_idval = (val.values[0] if len(val.values) == 1 else val.values)
|
||||
this_id.append(_idval(to_get_idval, argname, idx, idfn, nodeid=nodeid, config=config))
|
||||
return "-".join(this_id)
|
||||
else:
|
||||
return _ascii_escaped_by_config(id, config)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
from typing import List
|
||||
from typing import List, NamedTuple, Tuple, Any
|
||||
from typing import Optional
|
||||
from unittest import mock
|
||||
|
||||
|
@ -344,6 +344,61 @@ def test_parametrize_with_module(pytester: Pytester) -> None:
|
|||
assert passed[0].nodeid.split("::")[-1] == expected_id
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def pytester_internal_test_values():
|
||||
pytest.internal_test_values = [] # type: ignore[attr-defined]
|
||||
yield pytest.internal_test_values # type: ignore[attr-defined]
|
||||
del pytest.internal_test_values # type: ignore[attr-defined]
|
||||
|
||||
|
||||
def test_parametrize_with_nested_paramsets(pytester: Pytester, pytester_internal_test_values: List[Any]) -> None:
|
||||
"""Test parametrize with nested pytest.param objects in value"""
|
||||
case = NamedTuple(
|
||||
"case",
|
||||
[
|
||||
("expected_test_id", str),
|
||||
("expected_value", Tuple[Any, ...]),
|
||||
("expected_marks", Tuple[str, ...]),
|
||||
],
|
||||
)
|
||||
cases = (
|
||||
case("1-nested_2-3", (1, 2, 3), ("parametrize",)),
|
||||
case("one_two_three", (1, 2, 3), ("parametrize",)),
|
||||
case("1-nested_2-tuple_value", (1, 2, (3, 3)), ("parametrize",)),
|
||||
case("1-2-3", (1, 2, 3), ("parametrize", "a", "b", "c", "all",)),
|
||||
)
|
||||
pytester.makepyfile(
|
||||
"""
|
||||
import pytest
|
||||
@pytest.mark.parametrize(
|
||||
"a, b, c",
|
||||
[
|
||||
(1, pytest.param(2, id="nested_2"), pytest.param(3)),
|
||||
pytest.param(1, pytest.param(2, id="nested_2"), pytest.param(3), id="one_two_three"),
|
||||
(1, pytest.param(2, id="nested_2"), pytest.param((3, 3), id="tuple_value")),
|
||||
pytest.param(
|
||||
pytest.param(1, marks=pytest.mark.a),
|
||||
pytest.param(2, marks=pytest.mark.b),
|
||||
pytest.param(3, marks=pytest.mark.c),
|
||||
marks=pytest.mark.all
|
||||
),
|
||||
]
|
||||
)
|
||||
def test_func(a, b, c):
|
||||
pytest.internal_test_values.append((a, b, c))
|
||||
"""
|
||||
)
|
||||
rec = pytester.inline_run()
|
||||
items = [x.item for x in rec.getcalls("pytest_itemcollected")]
|
||||
passed, _, _ = rec.listoutcomes()
|
||||
for i, case_ in enumerate(cases):
|
||||
markers = {m.name for m in (items[i].iter_markers() or ())}
|
||||
expected_id = "test_func[" + case_.expected_test_id + "]"
|
||||
assert markers == set(case_.expected_marks)
|
||||
assert passed[i].nodeid.split("::")[-1] == expected_id
|
||||
assert pytester_internal_test_values[i] == case_.expected_value
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("expr", "expected_error"),
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue