@@ -929,7 +929,7 @@ def parametrize(
929929 ids = None ,
930930 scope = None ,
931931 * ,
932- _param_mark : Optional [Mark ] = None
932+ _param_mark : Optional [Mark ] = None ,
933933 ):
934934 """ Add new invocations to the underlying test function using the list
935935 of argvalues for the given argnames. Parametrization is performed
@@ -1002,6 +1002,8 @@ def parametrize(
10021002
10031003 arg_values_types = self ._resolve_arg_value_types (argnames , indirect )
10041004
1005+ self ._validate_explicit_parameters (argnames , indirect )
1006+
10051007 # Use any already (possibly) generated ids with parametrize Marks.
10061008 if _param_mark and _param_mark ._param_ids_from :
10071009 generated_ids = _param_mark ._param_ids_from ._param_ids_generated
@@ -1152,6 +1154,37 @@ def _validate_if_using_arg_names(self, argnames, indirect):
11521154 pytrace = False ,
11531155 )
11541156
1157+ def _validate_explicit_parameters (self , argnames , indirect ):
1158+ """
1159+ The argnames in *parametrize* should either be declared explicitly via
1160+ indirect list or in the function signature
1161+
1162+ :param List[str] argnames: list of argument names passed to ``parametrize()``.
1163+ :param indirect: same ``indirect`` parameter of ``parametrize()``.
1164+ :raise ValueError: if validation fails
1165+ """
1166+ if isinstance (indirect , bool ) and indirect is True :
1167+ return
1168+ parametrized_argnames = list ()
1169+ funcargnames = _pytest .compat .getfuncargnames (self .function )
1170+ if isinstance (indirect , Sequence ):
1171+ for arg in argnames :
1172+ if arg not in indirect :
1173+ parametrized_argnames .append (arg )
1174+ elif indirect is False :
1175+ parametrized_argnames = argnames
1176+
1177+ usefixtures = fixtures .get_use_fixtures_for_node (self .definition )
1178+
1179+ for arg in parametrized_argnames :
1180+ if arg not in funcargnames and arg not in usefixtures :
1181+ func_name = self .function .__name__
1182+ msg = (
1183+ 'In function "{func_name}":\n '
1184+ 'Parameter "{arg}" should be declared explicitly via indirect or in function itself'
1185+ ).format (func_name = func_name , arg = arg )
1186+ fail (msg , pytrace = False )
1187+
11551188
11561189def _find_parametrized_scope (argnames , arg2fixturedefs , indirect ):
11571190 """Find the most appropriate scope for a parametrized call based on its arguments.
0 commit comments