issue #308
first attempt, mark individual parametrize test instances with other marks (like xfail)
This commit is contained in:
parent
5a1ce3c45c
commit
5373a63008
|
@ -4,6 +4,7 @@ import inspect
|
||||||
import sys
|
import sys
|
||||||
import pytest
|
import pytest
|
||||||
from _pytest.main import getfslineno
|
from _pytest.main import getfslineno
|
||||||
|
from _pytest.mark import MarkDecorator, MarkInfo
|
||||||
from _pytest.monkeypatch import monkeypatch
|
from _pytest.monkeypatch import monkeypatch
|
||||||
from py._code.code import TerminalRepr
|
from py._code.code import TerminalRepr
|
||||||
|
|
||||||
|
@ -565,11 +566,13 @@ class CallSpec2(object):
|
||||||
self._globalid_args = set()
|
self._globalid_args = set()
|
||||||
self._globalparam = _notexists
|
self._globalparam = _notexists
|
||||||
self._arg2scopenum = {} # used for sorting parametrized resources
|
self._arg2scopenum = {} # used for sorting parametrized resources
|
||||||
|
self.keywords = {}
|
||||||
|
|
||||||
def copy(self, metafunc):
|
def copy(self, metafunc):
|
||||||
cs = CallSpec2(self.metafunc)
|
cs = CallSpec2(self.metafunc)
|
||||||
cs.funcargs.update(self.funcargs)
|
cs.funcargs.update(self.funcargs)
|
||||||
cs.params.update(self.params)
|
cs.params.update(self.params)
|
||||||
|
cs.keywords.update(self.keywords)
|
||||||
cs._arg2scopenum.update(self._arg2scopenum)
|
cs._arg2scopenum.update(self._arg2scopenum)
|
||||||
cs._idlist = list(self._idlist)
|
cs._idlist = list(self._idlist)
|
||||||
cs._globalid = self._globalid
|
cs._globalid = self._globalid
|
||||||
|
@ -593,7 +596,7 @@ class CallSpec2(object):
|
||||||
def id(self):
|
def id(self):
|
||||||
return "-".join(map(str, filter(None, self._idlist)))
|
return "-".join(map(str, filter(None, self._idlist)))
|
||||||
|
|
||||||
def setmulti(self, valtype, argnames, valset, id, scopenum=0):
|
def setmulti(self, valtype, argnames, valset, id, keywords, scopenum=0):
|
||||||
for arg,val in zip(argnames, valset):
|
for arg,val in zip(argnames, valset):
|
||||||
self._checkargnotcontained(arg)
|
self._checkargnotcontained(arg)
|
||||||
getattr(self, valtype)[arg] = val
|
getattr(self, valtype)[arg] = val
|
||||||
|
@ -605,6 +608,7 @@ class CallSpec2(object):
|
||||||
if val is _notexists:
|
if val is _notexists:
|
||||||
self._emptyparamspecified = True
|
self._emptyparamspecified = True
|
||||||
self._idlist.append(id)
|
self._idlist.append(id)
|
||||||
|
self.keywords.update(keywords)
|
||||||
|
|
||||||
def setall(self, funcargs, id, param):
|
def setall(self, funcargs, id, param):
|
||||||
for x in funcargs:
|
for x in funcargs:
|
||||||
|
@ -673,6 +677,18 @@ class Metafunc(FuncargnamesCompatAttr):
|
||||||
if not argvalues:
|
if not argvalues:
|
||||||
argvalues = [(_notexists,) * len(argnames)]
|
argvalues = [(_notexists,) * len(argnames)]
|
||||||
|
|
||||||
|
# these marks/keywords will be applied in Function init
|
||||||
|
newkeywords = {}
|
||||||
|
for i, argval in enumerate(argvalues):
|
||||||
|
newkeywords[i] = {}
|
||||||
|
if isinstance(argval, MarkDecorator):
|
||||||
|
# convert into a mark without the test content mixed in
|
||||||
|
newmark = MarkDecorator(argval.markname, argval.args[:-1], argval.kwargs)
|
||||||
|
newkeywords[i] = {newmark.markname: newmark}
|
||||||
|
|
||||||
|
argvalues = [av.args[-1] if isinstance(av, MarkDecorator) else av
|
||||||
|
for av in argvalues]
|
||||||
|
|
||||||
if scope is None:
|
if scope is None:
|
||||||
scope = "subfunction"
|
scope = "subfunction"
|
||||||
scopenum = scopes.index(scope)
|
scopenum = scopes.index(scope)
|
||||||
|
@ -691,7 +707,7 @@ class Metafunc(FuncargnamesCompatAttr):
|
||||||
assert len(valset) == len(argnames)
|
assert len(valset) == len(argnames)
|
||||||
newcallspec = callspec.copy(self)
|
newcallspec = callspec.copy(self)
|
||||||
newcallspec.setmulti(valtype, argnames, valset, ids[i],
|
newcallspec.setmulti(valtype, argnames, valset, ids[i],
|
||||||
scopenum)
|
newkeywords[i], scopenum)
|
||||||
newcalls.append(newcallspec)
|
newcalls.append(newcallspec)
|
||||||
self._calls = newcalls
|
self._calls = newcalls
|
||||||
|
|
||||||
|
@ -908,6 +924,9 @@ class Function(FunctionMixin, pytest.Item, FuncargnamesCompatAttr):
|
||||||
|
|
||||||
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
|
for name, val in (py.builtin._getfuncdict(self.obj) or {}).items():
|
||||||
self.keywords[name] = val
|
self.keywords[name] = val
|
||||||
|
if callspec:
|
||||||
|
for name, val in callspec.keywords.items():
|
||||||
|
self.keywords[name] = val
|
||||||
if keywords:
|
if keywords:
|
||||||
for name, val in keywords.items():
|
for name, val in keywords.items():
|
||||||
self.keywords[name] = val
|
self.keywords[name] = val
|
||||||
|
|
|
@ -577,4 +577,175 @@ class TestMetafuncFunctional:
|
||||||
"*3 passed*"
|
"*3 passed*"
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_mark_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.foo
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.bar((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
items = testdir.getitems(s)
|
||||||
|
assert len(items) == 3
|
||||||
|
for item in items:
|
||||||
|
assert 'foo' in item.keywords
|
||||||
|
assert 'bar' not in items[0].keywords
|
||||||
|
assert 'bar' in items[1].keywords
|
||||||
|
assert 'bar' not in items[2].keywords
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_select_individual_parametrize_instance_based_on_mark(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.foo((2, 3)),
|
||||||
|
(3, 4),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
rec = testdir.inline_run("-m", 'foo')
|
||||||
|
passed, skipped, fail = rec.listoutcomes()
|
||||||
|
assert len(passed) == 1
|
||||||
|
assert len(skipped) == 0
|
||||||
|
assert len(fail) == 0
|
||||||
|
|
||||||
|
@pytest.mark.xfail("is this important to support??")
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_nested_marks_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.foo(pytest.mark.bar((1, 3))),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
items = testdir.getitems(s)
|
||||||
|
assert len(items) == 3
|
||||||
|
for mark in ['foo', 'bar']:
|
||||||
|
assert mark not in items[0].keywords
|
||||||
|
assert mark in items[1].keywords
|
||||||
|
assert mark not in items[2].keywords
|
||||||
|
|
||||||
|
@pytest.mark.xfail(reason="is this important to support??")
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_nested_marks_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
mastermark = pytest.mark.foo(pytest.mark.bar)
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
mastermark((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
items = testdir.getitems(s)
|
||||||
|
assert len(items) == 3
|
||||||
|
for mark in ['foo', 'bar']:
|
||||||
|
assert mark not in items[0].keywords
|
||||||
|
assert mark in items[1].keywords
|
||||||
|
assert mark not in items[2].keywords
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_simple_xfail_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.xfail((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
# xfail is skip??
|
||||||
|
reprec.assertoutcome(passed=2, skipped=1)
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_xfail_with_arg_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.xfail("sys.version > 0")((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
reprec.assertoutcome(passed=2, skipped=1)
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_xfail_with_kwarg_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.xfail(reason="some bug")((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
reprec.assertoutcome(passed=2, skipped=1)
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_xfail_with_arg_and_kwarg_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.xfail("sys.version > 0", reason="some bug")((1, 3)),
|
||||||
|
(2, 3),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
reprec.assertoutcome(passed=2, skipped=1)
|
||||||
|
|
||||||
|
@pytest.mark.issue308
|
||||||
|
def test_xfail_is_xpass_on_individual_parametrize_instance(self, testdir):
|
||||||
|
s = """
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(("input", "expected"), [
|
||||||
|
(1, 2),
|
||||||
|
pytest.mark.xfail("sys.version > 0", reason="some bug")((2, 3)),
|
||||||
|
(3, 4),
|
||||||
|
])
|
||||||
|
def test_increment(input, expected):
|
||||||
|
assert input + 1 == expected
|
||||||
|
"""
|
||||||
|
testdir.makepyfile(s)
|
||||||
|
reprec = testdir.inline_run()
|
||||||
|
# xpass is fail, obviously :)
|
||||||
|
reprec.assertoutcome(passed=2, failed=1)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue