diff --git a/AUTHORS b/AUTHORS index 2d59a1b0fbe..9b4b8b8ccdf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -13,6 +13,7 @@ Alexei Kozlenok Anatoly Bubenkoff Anders Hovmöller Andras Tim +Andrea Cimatoribus Andreas Zeidler Andrzej Ostrowski Andy Freeland diff --git a/changelog/3849.feature.rst b/changelog/3849.feature.rst new file mode 100644 index 00000000000..26cbfe7b4de --- /dev/null +++ b/changelog/3849.feature.rst @@ -0,0 +1 @@ +Add ``empty_parameter_set_mark=fail_at_collect`` ini option for raising an exception when parametrize collects an empty set. diff --git a/doc/en/reference.rst b/doc/en/reference.rst index 52d83cf6ee3..f6a204fff70 100644 --- a/doc/en/reference.rst +++ b/doc/en/reference.rst @@ -976,6 +976,7 @@ passed multiple times. The expected format is ``name=value``. For example:: * ``skip`` skips tests with an empty parameterset (default) * ``xfail`` marks tests with an empty parameterset as xfail(run=False) + * ``fail_at_collect`` raises an exception if parametrize collects an empty parameter set .. code-block:: ini diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index e3918ca6a4f..eb25cd4aa59 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -163,9 +163,9 @@ def pytest_configure(config): empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION) - if empty_parameterset not in ("skip", "xfail", None, ""): + if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""): raise UsageError( - "{!s} must be one of skip and xfail," + "{!s} must be one of skip, xfail or fail_at_collect" " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset) ) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 8e8937d592d..2c4635bf40e 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -32,11 +32,19 @@ def istestfunc(func): def get_empty_parameterset_mark(config, argnames, func): + from ..nodes import Collector + requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION) if requested_mark in ("", None, "skip"): mark = MARK_GEN.skip elif requested_mark == "xfail": mark = MARK_GEN.xfail(run=False) + elif requested_mark == "fail_at_collect": + f_name = func.__name__ + _, lineno = getfslineno(func) + raise Collector.CollectError( + "Empty parameter set in '%s' at line %d" % (f_name, lineno) + ) else: raise LookupError(requested_mark) fs, lineno = getfslineno(func) diff --git a/testing/test_mark.py b/testing/test_mark.py index 9dad7a16509..baf1d6f406f 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -13,7 +13,7 @@ transfer_markers, EMPTY_PARAMETERSET_OPTION, ) -from _pytest.nodes import Node +from _pytest.nodes import Node, Collector ignore_markinfo = pytest.mark.filterwarnings( "ignore:MarkInfo objects:pytest.RemovedInPytest4Warning" @@ -1091,7 +1091,14 @@ def test__eq__(self, lhs, rhs, expected): @pytest.mark.parametrize("mark", [None, "", "skip", "xfail"]) def test_parameterset_for_parametrize_marks(testdir, mark): if mark is not None: - testdir.makeini("[pytest]\n{}={}".format(EMPTY_PARAMETERSET_OPTION, mark)) + testdir.makeini( + """ + [pytest] + {}={} + """.format( + EMPTY_PARAMETERSET_OPTION, mark + ) + ) config = testdir.parseconfig() from _pytest.mark import pytest_configure, get_empty_parameterset_mark @@ -1107,6 +1114,34 @@ def test_parameterset_for_parametrize_marks(testdir, mark): assert result_mark.kwargs.get("run") is False +def test_parameterset_for_fail_at_collect(testdir): + testdir.makeini( + """ + [pytest] + {}=fail_at_collect + """.format( + EMPTY_PARAMETERSET_OPTION + ) + ) + + config = testdir.parseconfig() + from _pytest.mark import pytest_configure, get_empty_parameterset_mark + from _pytest.compat import getfslineno + + pytest_configure(config) + + test_func = all + func_name = test_func.__name__ + _, func_lineno = getfslineno(test_func) + expected_errmsg = r"Empty parameter set in '%s' at line %d" % ( + func_name, + func_lineno, + ) + + with pytest.raises(Collector.CollectError, match=expected_errmsg): + get_empty_parameterset_mark(config, ["a"], test_func) + + def test_parameterset_for_parametrize_bad_markname(testdir): with pytest.raises(pytest.UsageError): test_parameterset_for_parametrize_marks(testdir, "bad")