diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 000000000..112d642aa Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index a6503bf1d..b32a31874 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -162,25 +162,24 @@ class ParameterSet(NamedTuple): del argvalues if parameters: + # 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..18bb9057c 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -1371,11 +1371,19 @@ class Metafunc: # num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849 if num_ids != len(parametersets) and num_ids != 0: - msg = "In {}: {} parameter sets specified, with different number of ids: {}" - fail(msg.format(func_name, len(parametersets), num_ids), pytrace=False) + # Construct a string representation of the expected parameter sets + expected_paramsets = len(parametersets) + + msg = ( + f"In {func_name}: \n\n" + f" Specified {expected_paramsets} parameter sets with {num_ids} different ids. \n" + f" Ensure all subparameters are correctly grouped within a single set of quotation marks." + ) + fail(msg, pytrace=False) return list(itertools.islice(ids, num_ids)) + def _resolve_args_directness( self, argnames: Sequence[str], @@ -1402,8 +1410,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, 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" @@ -1415,6 +1439,9 @@ class Metafunc: ) return arg_directness + + + def _validate_if_using_arg_names( self, argnames: Sequence[str],