Request #714: Apply indirect=True on particular argnames

This commit is contained in:
elizabeth 2015-08-02 16:40:40 +03:00
parent ae28e4ba0f
commit 2fc7aede0b
2 changed files with 57 additions and 5 deletions

View File

@ -761,11 +761,12 @@ class CallSpec2(object):
def id(self):
return "-".join(map(str, filter(None, self._idlist)))
def setmulti(self, valtype, argnames, valset, id, keywords, scopenum,
def setmulti(self, valtypes, argnames, valset, id, keywords, scopenum,
param_index):
for arg,val in zip(argnames, valset):
self._checkargnotcontained(arg)
getattr(self, valtype)[arg] = val
valtype_for_arg = valtypes[arg]
getattr(self, valtype_for_arg)[arg] = val
self.indices[arg] = param_index
self._arg2scopenum[arg] = scopenum
if val is _notexists:
@ -844,7 +845,9 @@ class Metafunc(FuncargnamesCompatAttr):
where each tuple-element specifies a value for its respective
argname.
:arg indirect: if True each argvalue corresponding to an argname will
:arg indirect: The list of argnames or boolean. A list of arguments'
names (subset of argnames). If True the list contains all names from
the argnames. Each argvalue corresponding to an argname in this list will
be passed as request.param to its respective argname fixture
function so that it can perform more expensive setups during the
setup phase of a test rather than at collection time.
@ -889,13 +892,22 @@ class Metafunc(FuncargnamesCompatAttr):
if scope is None:
scope = "function"
scopenum = scopes.index(scope)
valtypes = {arg: "funcargs" for arg in argnames}
if not indirect:
#XXX should we also check for the opposite case?
for arg in argnames:
if arg not in self.fixturenames:
raise ValueError("%r uses no fixture %r" %(
self.function, arg))
valtype = indirect and "params" or "funcargs"
else:
if not isinstance(indirect, (tuple, list)):
valtypes = {arg: "params" for arg in argnames}
else:
for arg in indirect:
if arg not in argnames:
raise ValueError("indirect: fixture %r doesn't exist" %(
arg))
valtypes[arg] = "params"
idfn = None
if callable(ids):
idfn = ids
@ -910,7 +922,7 @@ class Metafunc(FuncargnamesCompatAttr):
for param_index, valset in enumerate(argvalues):
assert len(valset) == len(argnames)
newcallspec = callspec.copy(self)
newcallspec.setmulti(valtype, argnames, valset, ids[param_index],
newcallspec.setmulti(valtypes, argnames, valset, ids[param_index],
newkeywords.get(param_index, {}), scopenum,
param_index)
newcalls.append(newcallspec)

View File

@ -220,6 +220,46 @@ class TestMetafunc:
assert metafunc._calls[0].params == dict(x=1,y=2, unnamed=1)
assert metafunc._calls[1].params == dict(x=1,y=3, unnamed=1)
def test_parametrize_indirect_list(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize('x, y', [('a', 'b')], indirect=['x'])
assert metafunc._calls[0].funcargs == dict(y='b')
assert metafunc._calls[0].params == dict(x='a')
def test_parametrize_indirect_list_all(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize('x, y', [('a', 'b')], indirect=['x', 'y'])
assert metafunc._calls[0].funcargs == {}
assert metafunc._calls[0].params == dict(x='a', y='b')
def test_parametrize_indirect_list_empty(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
metafunc.parametrize('x, y', [('a', 'b')], indirect=[])
assert metafunc._calls[0].funcargs == dict(x='a', y='b')
assert metafunc._calls[0].params == {}
def test_parametrize_indirect_list_functional(self, testdir):
testdir.makepyfile("""
def pytest_generate_tests(metafunc):
metafunc.parametrize('x, y', [('a', 'b')], indirect=['x'])
def pytest_funcarg__x(request):
return request.param * 3
def pytest_funcarg__y(request):
return request.param * 2
def test_simple(x,y):
assert len(x) == 3
assert len(y) == 1
""")
result = testdir.runpytest("-v")
result.stdout.fnmatch_lines([
"*test_simple*a-b*",
"*1 passed*",
])
def test_addcalls_and_parametrize_indirect(self):
def func(x, y): pass
metafunc = self.Metafunc(func)