diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index a6503bf1d..c2057e75d 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -165,22 +165,20 @@ class ParameterSet(NamedTuple): # Check all parameter sets have the correct number of values. for param in parameters: if len(param.values) != len(argnames): + # Construct a string representation of the expected parameter names + expected_argnames = ", ".join(argnames) + # Construct a string representation of the provided parameter values + provided_values = ", ".join(map(repr, param.values)) msg = ( - '{nodeid}: in "parametrize" the number of names ({names_len}):\n' - " {names}\n" - "must be equal to the number of values ({values_len}):\n" - " {values}" - ) - fail( - msg.format( - nodeid=nodeid, - values=param.values, - names=argnames, - names_len=len(argnames), - values_len=len(param.values), - ), - pytrace=False, + f'{nodeid}: \n\n Error in parameterization for test "{func.__name__}".\n ' + f"The number of specified parameters ({len(argnames)}) " + f"does not match the number of provided values ({len(param.values)}): {provided_values}. \n" + f" Please ensure that the correct number of parameter names " + f"({len(param.values)}) are separated by commas within quotes.\n\n" + f'Require more than parameter names: "{expected_argnames}"' ) + + fail(msg, pytrace=False) else: # Empty parameter set (likely computed at runtime): create a single # parameter set with NOTSET values, with the "empty parameter set" mark applied to it. diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 5e059f2c4..de23f8026 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1402,8 +1402,24 @@ class Metafunc: arg_directness = dict.fromkeys(argnames, "direct") for arg in indirect: if arg not in argnames: + # Construct a list of valid parameter names + valid_params = ", ".join([f'"{name}"' for name in argnames]) + + # Construct a string representing the expected number of parameters + expected_param_count = len(indirect[0]) + + # Construct a string representing the actual number of parameters provided + actual_param_count = len(argnames) + fail( - f"In {self.function.__name__}: indirect fixture '{arg}' doesn't exist", + f"In function {self.function.__name__}: {argnames} is not a valid parameter. " + f"Expected {expected_param_count} sub parameters, " + f"but only {actual_param_count} were provided. \n\n" + f"Make sure to pass parameter names as strings without quotes, separated by commas, \n " + f"e.g., '@pytest.mark.parametrize({valid_params}, )'" + f"\n\n" + f"Or if multiple parameters are used, separate them by commas. \n " + f"e.g., '@pytest.mark.parametrize(\"arg1, arg2\", )'", pytrace=False, ) arg_directness[arg] = "indirect" diff --git a/testing/local_testing/local_test_0.py b/testing/local_testing/local_test_0.py index 76c079dea..fbc477f15 100644 --- a/testing/local_testing/local_test_0.py +++ b/testing/local_testing/local_test_0.py @@ -1,8 +1,8 @@ import pytest -@pytest.mark.parametrize("arg1,arg2", [(1, 1)]) -def test_parametrization(arg1, arg2): +@pytest.mark.parametrize("arg1, arg2", [(1, 1)]) +def test_parametrization(arg1: int, arg2: int) -> None: assert arg1 == arg2 assert arg1 + 1 == arg2 + 1 diff --git a/testing/local_testing/local_test_test.py b/testing/local_testing/local_test_test.py index 23ac56060..cb1c534bd 100644 --- a/testing/local_testing/local_test_test.py +++ b/testing/local_testing/local_test_test.py @@ -9,5 +9,5 @@ result_index = [(1, 2, 3), (-1, 1, 0), (0, 0, 0), (5, -3, 2), (1, 1, 2)] @pytest.mark.parametrize("a, b,expected_result", result_index) -def test_add(a, b, expected_result): +def test_add(a: int, b: int, expected_result: int) -> None: assert add_function.add(a, b) == expected_result diff --git a/testing/test_mark.py b/testing/test_mark.py index 2896afa45..eefedf15e 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -419,10 +419,13 @@ def test_parametrized_collect_with_wrong_args(pytester: Pytester) -> None: result = pytester.runpytest(py_file) result.stdout.fnmatch_lines( [ - 'test_parametrized_collect_with_wrong_args.py::test_func: in "parametrize" the number of names (2):', - " ['foo', 'bar']", - "must be equal to the number of values (3):", - " (1, 2, 3)", + "test_parametrized_collect_with_wrong_args.py::test_func: ", + "", + ' Error in parameterization for test "test_func".', + " The number of specified parameters (2) does not match the number of provided values (3): 1, 2, 3. ", + " Please ensure that the correct number of parameter names (3) are separated by commas within quotes.", + "", + 'Require more than parameter names: "foo, bar"', ] )