fix issue91 introduce new py.test.xfail(reason) helper

to imperatively mark a test as expected to fail. Can
be used from within setup and test functions. This is
useful especially for parametrized tests when certain
configurations are expected-to-fail.  In this case the
declarative approach with the @py.test.mark.xfail cannot
be used as it would mark all configurations as xfail.

--HG--
branch : trunk
This commit is contained in:
holger krekel 2010-05-20 13:29:51 +02:00
parent eac0345689
commit 925f75088d
4 changed files with 69 additions and 3 deletions

View File

@ -9,6 +9,14 @@ Changes between 1.3.0 and 1.3.1
- fix issue95: late-import zlib so that it's not required - fix issue95: late-import zlib so that it's not required
for general py.test startup. for general py.test startup.
- fix issue91: introduce new py.test.xfail(reason) helper
to imperatively mark a test as expected to fail. Can
be used from within setup and test functions. This is
useful especially for parametrized tests when certain
configurations are expected-to-fail. In this case the
declarative approach with the @py.test.mark.xfail cannot
be used as it would mark all configurations as xfail.
- make py.test.cmdline.main() return the exitstatus - make py.test.cmdline.main() return the exitstatus
instead of raising (which is still done by py.cmdline.pytest()) instead of raising (which is still done by py.cmdline.pytest())
and make it so that py.test.cmdline.main() can be called and make it so that py.test.cmdline.main() can be called

View File

@ -10,6 +10,7 @@ def pytest_namespace():
'skip' : skip, 'skip' : skip,
'importorskip' : importorskip, 'importorskip' : importorskip,
'fail' : fail, 'fail' : fail,
'xfail' : xfail,
'exit' : exit, 'exit' : exit,
} }
@ -295,6 +296,10 @@ class Failed(OutcomeException):
""" raised from an explicit call to py.test.fail() """ """ raised from an explicit call to py.test.fail() """
__module__ = 'builtins' __module__ = 'builtins'
class XFailed(OutcomeException):
""" raised from an explicit call to py.test.xfail() """
__module__ = 'builtins'
class ExceptionFailure(Failed): class ExceptionFailure(Failed):
""" raised by py.test.raises on an exception-assertion mismatch. """ """ raised by py.test.raises on an exception-assertion mismatch. """
def __init__(self, expr, expected, msg=None, excinfo=None): def __init__(self, expr, expected, msg=None, excinfo=None):
@ -335,6 +340,14 @@ def fail(msg=""):
fail.Exception = Failed fail.Exception = Failed
def xfail(reason=""):
""" xfail an executing test or setup functions, taking an optional
reason string.
"""
__tracebackhide__ = True
raise XFailed(reason)
xfail.Exception = XFailed
def raises(ExpectedException, *args, **kwargs): def raises(ExpectedException, *args, **kwargs):
""" if args[0] is callable: raise AssertionError if calling it with """ if args[0] is callable: raise AssertionError if calling it with
the remaining arguments does not raise the expected exception. the remaining arguments does not raise the expected exception.

View File

@ -185,9 +185,17 @@ def pytest_runtest_setup(item):
def pytest_runtest_makereport(__multicall__, item, call): def pytest_runtest_makereport(__multicall__, item, call):
if not isinstance(item, py.test.collect.Function): if not isinstance(item, py.test.collect.Function):
return return
evalxfail = getattr(item, '_evalxfail', None) if not (call.excinfo and
if not evalxfail: call.excinfo.errisinstance(py.test.xfail.Exception)):
return evalxfail = getattr(item, '_evalxfail', None)
if not evalxfail:
return
if call.excinfo and call.excinfo.errisinstance(py.test.xfail.Exception):
rep = __multicall__.execute()
rep.keywords['xfail'] = "reason: " + call.excinfo.value.msg
rep.skipped = True
rep.failed = False
return rep
if call.when == "setup": if call.when == "setup":
rep = __multicall__.execute() rep = __multicall__.execute()
if rep.skipped and evalxfail.istrue(): if rep.skipped and evalxfail.istrue():

View File

@ -169,6 +169,43 @@ class TestXFail:
]) ])
assert result.ret == 1 assert result.ret == 1
def test_xfail_imperative(self, testdir):
p = testdir.makepyfile("""
import py
def test_this():
py.test.xfail("hello")
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"*1 xfailed*",
])
result = testdir.runpytest(p, "-rx")
result.stdout.fnmatch_lines([
"*XFAIL*test_this*reason:*hello*",
])
def test_xfail_imperative_in_setup_function(self, testdir):
p = testdir.makepyfile("""
import py
def setup_function(function):
py.test.xfail("hello")
def test_this():
assert 0
""")
result = testdir.runpytest(p)
result.stdout.fnmatch_lines([
"*1 xfailed*",
])
result = testdir.runpytest(p, "-rx")
result.stdout.fnmatch_lines([
"*XFAIL*test_this*reason:*hello*",
])
class TestSkipif: class TestSkipif:
def test_skipif_conditional(self, testdir): def test_skipif_conditional(self, testdir):
item = testdir.getitem(""" item = testdir.getitem("""