diff --git a/CHANGELOG b/CHANGELOG index 800cb05e3..69ddc9bca 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,14 @@ -$Id: CHANGELOG 57548 2008-08-21 12:12:20Z hpk $ +$Id: CHANGELOG 58297 2008-09-21 12:50:56Z hpk $ Changes between 0.9.2 and 1.0 (UNRELEASED) ============================================= +* py.test.skip(ifraises=execstring) allows to + conditionally skip, e.g. ifraises="import docutils" + will skip if there is no docutils installed. + * revised internal py.test architecture + * new py.process.ForkedFunc object allowing to fork execution of a function to a sub process and getting a result back. diff --git a/py/doc/test.txt b/py/doc/test.txt index 393f38dea..545ab0e43 100644 --- a/py/doc/test.txt +++ b/py/doc/test.txt @@ -86,6 +86,24 @@ asserts that the given ``Exception`` is raised. The reporter will provide you with helpful output in case of failures such as *no exception* or *wrong exception*. +Skipping tests +---------------------------------------- + +If you want to skip tests you can use ``py.test.skip`` within +test or setup functions. Examples:: + + py.test.skip("message") + py.test.skip(ifraises="import docutils") + py.test.skip(ifraises=""" + import somepkg + assert somepkg.__version__.startswith("2") + """) + +The first skip will cause unconditional skipping +The second skip will only cause skipping if +``docutils`` is not importable. +The third form will cause skipping if ``somepkg`` +is not importable or is not at least version "2". automatic collection of tests on all levels ------------------------------------------- diff --git a/py/test/outcome.py b/py/test/outcome.py index 81b5e6e77..71e60f8f4 100644 --- a/py/test/outcome.py +++ b/py/test/outcome.py @@ -49,9 +49,26 @@ def exit(msg): __tracebackhide__ = True raise Exit(msg) -def skip(msg=""): - """ skip with the given Message. """ +def skip(msg="", ifraises=None): + """ (conditionally) skip this test/module/conftest. + + ifraises: + if "exec ifraises in {'py': py}" raises an exception + skip this test. + msg: use this message when skipping. + """ __tracebackhide__ = True + if ifraises is not None: + ifraises = py.code.Source(ifraises).compile() + try: + exec ifraises in {'py': py} + except (KeyboardInterrupt, SystemExit): + raise + except Exception, e: + if not msg: + msg = repr(e) + else: + return raise Skipped(msg=msg) def fail(msg="unknown failure"): @@ -66,16 +83,15 @@ def raises(ExpectedException, *args, **kwargs): __tracebackhide__ = True assert args if isinstance(args[0], str): - expr, = args - assert isinstance(expr, str) + code, = args + assert isinstance(code, str) frame = sys._getframe(1) loc = frame.f_locals.copy() loc.update(kwargs) #print "raises frame scope: %r" % frame.f_locals - source = py.code.Source(expr) try: - exec source.compile() in frame.f_globals, loc - #del __traceback__ + code = py.code.Source(code).compile() + exec code in frame.f_globals, loc # XXX didn'T mean f_globals == f_locals something special? # this is destroyed here ... except ExpectedException: @@ -85,7 +101,6 @@ def raises(ExpectedException, *args, **kwargs): assert callable try: func(*args[1:], **kwargs) - #del __traceback__ except ExpectedException: return py.code.ExceptionInfo() k = ", ".join(["%s=%r" % x for x in kwargs.items()]) diff --git a/py/test/testing/test_collect.py b/py/test/testing/test_collect.py index 00e815f6e..f9b8757af 100644 --- a/py/test/testing/test_collect.py +++ b/py/test/testing/test_collect.py @@ -427,29 +427,13 @@ class Testgenitems: ev = failures[0] assert ev.outcome.longrepr.reprcrash.message.startswith("SyntaxError") - def test_skip_at_module_level(self): - self.tmp.ensure("test_module.py").write(py.code.Source(""" - import py - py.test.skip('xxx') - """)) - items, events = self._genitems() - funcs = [x for x in items if isinstance(x, event.ItemStart)] - assert not funcs - assert not items - l = [x for x in events - if isinstance(x, event.CollectionReport) - and x.colitem.name == 'test_module.py'] - assert len(l) == 1 - ev = l[0] - assert ev.skipped - def test_example_items1(self): self.tmp.ensure("test_example.py").write(py.code.Source(''' - def test_one(): + def testone(): pass class TestX: - def test_method_one(self): + def testmethod_one(self): pass class TestY(TestX): @@ -457,17 +441,17 @@ class Testgenitems: ''')) items, events = self._genitems() assert len(items) == 3 - assert items[0].name == 'test_one' - assert items[1].name == 'test_method_one' - assert items[2].name == 'test_method_one' + assert items[0].name == 'testone' + assert items[1].name == 'testmethod_one' + assert items[2].name == 'testmethod_one' # let's also test getmodpath here - assert items[0].getmodpath() == "test_one" - assert items[1].getmodpath() == "TestX.test_method_one" - assert items[2].getmodpath() == "TestY.test_method_one" + assert items[0].getmodpath() == "testone" + assert items[1].getmodpath() == "TestX.testmethod_one" + assert items[2].getmodpath() == "TestY.testmethod_one" s = items[0].getmodpath(stopatmodule=False) - assert s == "test_example_items1.test_example.test_one" + assert s == "test_example_items1.test_example.testone" print s def test_collect_doctest_files_with_test_prefix(self): diff --git a/py/test/testing/test_outcome.py b/py/test/testing/test_outcome.py index 8b97b2e01..6589dbdb2 100644 --- a/py/test/testing/test_outcome.py +++ b/py/test/testing/test_outcome.py @@ -1,6 +1,7 @@ import py import marshal +from py.__.test.outcome import Skipped class TestRaises: def test_raises(self): @@ -58,3 +59,28 @@ def test_deprecated_explicit_call(): py.test.deprecated_call(dep_explicit, 0) py.test.deprecated_call(dep_explicit, 0) + + +def test_skip_simple(): + excinfo = py.test.raises(Skipped, 'py.test.skip("xxx")') + assert excinfo.traceback[-1].frame.code.name == "skip" + assert excinfo.traceback[-1].ishidden() + +def test_skip_ifraises(): + excinfo = py.test.raises(Skipped, ''' + py.test.skip(ifraises=""" + import lky + """) + ''') + assert excinfo.traceback[-1].frame.code.name == "skip" + assert excinfo.traceback[-1].ishidden() + assert excinfo.value.msg.startswith("ImportError") + +def test_skip_ifraises_syntaxerror(): + try: + excinfo = py.test.raises(SyntaxError, ''' + py.test.skip(ifraises="x y z")''') + except Skipped: + py.test.fail("should not skip") + assert not excinfo.traceback[-1].ishidden() +