Merge branch 'master' of git://github.com/Elizaveta239/pytest into Elizaveta239-master

Fixed merge conflict in CHANGELOG
This commit is contained in:
Brianna Laugher 2015-08-08 18:54:53 +02:00
commit 40fa7b25c5
5 changed files with 125 additions and 7 deletions

View File

@ -26,6 +26,7 @@ Daniel Nuri
Dave Hunt
David Mohr
Eduardo Schettino
Elizaveta Shashkova
Eric Siegerman
Florian Bruhin
Edison Gustavo Muenz

View File

@ -123,6 +123,10 @@
- fix issue890: changed extension of all documentation files from ``txt`` to
``rst``. Thanks to Abhijeet for the PR.
- fix issue714: add ability to apply indirect=True parameter on particular argnames.
Thanks Elizaveta239.
2.7.3 (compared to 2.7.2)
-----------------------------

View File

@ -779,11 +779,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:
@ -850,7 +851,7 @@ class Metafunc(FuncargnamesCompatAttr):
""" Add new invocations to the underlying test function using the list
of argvalues for the given argnames. Parametrization is performed
during the collection phase. If you need to setup expensive resources
see about setting indirect=True to do it rather at test setup time.
see about setting indirect to do it rather at test setup time.
:arg argnames: a comma-separated string denoting one or more argument
names, or a list/tuple of argument strings.
@ -862,7 +863,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.
@ -907,13 +910,23 @@ class Metafunc(FuncargnamesCompatAttr):
if scope is None:
scope = "function"
scopenum = scopes.index(scope)
if not indirect:
valtypes = {}
if indirect is True:
valtypes = dict.fromkeys(argnames, "params")
elif indirect is False:
valtypes = dict.fromkeys(argnames, "funcargs")
#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"
elif isinstance(indirect, (tuple, list)):
valtypes = dict.fromkeys(argnames, "funcargs")
for arg in indirect:
if arg not in argnames:
raise ValueError("indirect given to %r: fixture %r doesn't exist" %(
self.function, arg))
valtypes[arg] = "params"
idfn = None
if callable(ids):
idfn = ids
@ -928,7 +941,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

@ -280,6 +280,46 @@ The first invocation with ``db == "DB1"`` passed while the second with ``db == "
.. regendoc:wipe
Apply indirect on particular arguments
---------------------------------------------------
Very often parametrization uses more than one argument name. There is opportunity to apply ``indirect``
parameter on particular arguments. It can be done by passing list or tuple of
arguments' names to ``indirect``. In the example below there is a function ``test_indirect`` which uses
two fixtures: ``x`` and ``y``. Here we give to indirect the list, which contains the name of the
fixture ``x``. The indirect parameter will be applied to this argument only, and the value ``a``
will be passed to respective fixture function.
# content of test_indirect_list.py
import pytest
@pytest.fixture(scope='function')
def x(request):
return request.param * 3
@pytest.fixture(scope='function')
def y(request):
return request.param * 2
@pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['x'])
def test_indirect(x,y):
assert x == 'aaa'
assert y == 'b'
The result of this test will be successful:
$ py.test test_indirect_list.py --collect-only
============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.8.0.dev4, py-1.4.30, pluggy-0.3.0
rootdir: /home/elizabeth/work/pytest, inifile: tox.ini
collected 1 items
<Module 'testing/test_argnames.py'>
<Function 'test_simple[a-b]'>
=============================== in 0.02 seconds ===============================
.. regendoc:wipe
Parametrizing test methods through per-class configuration
--------------------------------------------------------------

View File

@ -208,6 +208,7 @@ class TestMetafunc:
assert metafunc._calls[0].id == "0-2"
assert metafunc._calls[1].id == "0-3"
@pytest.mark.issue714
def test_parametrize_indirect(self):
def func(x, y): pass
metafunc = self.Metafunc(func)
@ -220,6 +221,65 @@ 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)
@pytest.mark.issue714
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')
@pytest.mark.issue714
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')
@pytest.mark.issue714
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 == {}
@pytest.mark.issue714
def test_parametrize_indirect_list_functional(self, testdir):
"""
Test parametrization with 'indirect' parameter applied on
particular arguments.
:param testdir: the instance of Testdir class, a temporary
test directory.
"""
testdir.makepyfile("""
import pytest
@pytest.fixture(scope='function')
def x(request):
return request.param * 3
@pytest.fixture(scope='function')
def y(request):
return request.param * 2
@pytest.mark.parametrize('x, y', [('a', 'b')], indirect=['x'])
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*",
])
@pytest.mark.issue714
def test_parametrize_indirect_list_error(self, testdir):
def func(x, y): pass
metafunc = self.Metafunc(func)
with pytest.raises(ValueError):
metafunc.parametrize('x, y', [('a', 'b')], indirect=['x', 'z'])
def test_addcalls_and_parametrize_indirect(self):
def func(x, y): pass
metafunc = self.Metafunc(func)