From 9be1cd80070132dec423dc394866ec6b98f66b0e Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 24 Nov 2010 11:48:55 +0100 Subject: [PATCH] fix #6 : allow skip/xfail/pdb with trial by hacking the raw exception info out from trial --- _pytest/pdb.py | 4 +- _pytest/unittest.py | 35 +++++++++++-- pytest.py | 2 +- setup.py | 2 +- testing/test_unittest.py | 104 +++++++++++++++++++++++++++++++++++++++ tox.ini | 7 +++ 6 files changed, 146 insertions(+), 8 deletions(-) diff --git a/_pytest/pdb.py b/_pytest/pdb.py index cb870a1c0..507f93d7a 100644 --- a/_pytest/pdb.py +++ b/_pytest/pdb.py @@ -44,11 +44,11 @@ def pytest_runtest_makereport(): class PdbInvoke: @pytest.mark.tryfirst def pytest_runtest_makereport(self, item, call, __multicall__): + rep = __multicall__.execute() if not call.excinfo or \ call.excinfo.errisinstance(pytest.skip.Exception) or \ call.excinfo.errisinstance(py.std.bdb.BdbQuit): - return - rep = __multicall__.execute() + return rep if "xfail" in rep.keywords: return rep # we assume that the above execute() suspended capturing diff --git a/_pytest/unittest.py b/_pytest/unittest.py index 28353f4f8..35367e7b0 100644 --- a/_pytest/unittest.py +++ b/_pytest/unittest.py @@ -44,8 +44,8 @@ class TestCaseFunction(pytest.Function): pass def _addexcinfo(self, rawexcinfo): - #__tracebackhide__ = True - assert rawexcinfo + # unwrap potential exception info (see twisted trial support below) + rawexcinfo = getattr(rawexcinfo, '_rawexcinfo', rawexcinfo) try: self._excinfo = py.code.ExceptionInfo(rawexcinfo) except TypeError: @@ -60,10 +60,10 @@ class TestCaseFunction(pytest.Function): except: pytest.fail("ERROR: Unknown Incompatible Exception " "representation:\n%r" %(rawexcinfo,), pytrace=False) - except pytest.fail.Exception: - self._excinfo = py.code.ExceptionInfo() except KeyboardInterrupt: raise + except pytest.fail.Exception: + self._excinfo = py.code.ExceptionInfo() def addError(self, testcase, rawexcinfo): self._addexcinfo(rawexcinfo) @@ -84,3 +84,30 @@ def pytest_runtest_makereport(item, call): call.excinfo = item._excinfo item._excinfo = None del call.result + +# twisted trial support +def pytest_runtest_protocol(item, __multicall__): + if isinstance(item, TestCaseFunction): + if 'twisted.trial.unittest' in sys.modules: + ut = sys.modules['twisted.python.failure'] + Failure__init__ = ut.Failure.__init__.im_func + check_testcase_implements_trial_reporter() + def excstore(self, exc_value=None, exc_type=None, exc_tb=None): + if exc_value is None: + self._rawexcinfo = sys.exc_info() + else: + self._rawexcinfo = (exc_value, exc_type, exc_tb) + Failure__init__(self, exc_value, exc_type, exc_tb) + ut.Failure.__init__ = excstore + try: + return __multicall__.execute() + finally: + ut.Failure.__init__ = Failure__init__ + +def check_testcase_implements_trial_reporter(done=[]): + if done: + return + from zope.interface import classImplements + from twisted.trial.itrial import IReporter + classImplements(TestCaseFunction, IReporter) + done.append(1) diff --git a/pytest.py b/pytest.py index d2c9120c1..1612dd640 100644 --- a/pytest.py +++ b/pytest.py @@ -5,7 +5,7 @@ see http://pytest.org for documentation and details (c) Holger Krekel and others, 2004-2010 """ -__version__ = '2.0.0.dev36' +__version__ = '2.0.0.dev37' __all__ = ['main'] from _pytest.core import main, UsageError, _preloadplugins diff --git a/setup.py b/setup.py index 5a83a9d3b..9ed4c5e64 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,7 @@ def main(): name='pytest', description='py.test: simple powerful testing with Python', long_description = long_description, - version='2.0.0.dev36', + version='2.0.0.dev37', url='http://pytest.org', license='MIT license', platforms=['unix', 'linux', 'osx', 'cygwin', 'win32'], diff --git a/testing/test_unittest.py b/testing/test_unittest.py index ecd0b6131..76eb31741 100644 --- a/testing/test_unittest.py +++ b/testing/test_unittest.py @@ -185,3 +185,107 @@ def test_testcase_totally_incompatible_exception_info(testdir): item.addError(None, 42) excinfo = item._excinfo assert 'ERROR: Unknown Incompatible' in str(excinfo.getrepr()) + + + +class TestTrialUnittest: + def setup_class(cls): + pytest.importorskip("twisted.trial.unittest") + + def test_trial_exceptions_with_skips(self, testdir): + testdir.makepyfile(""" + from twisted.trial import unittest + import pytest + class TC(unittest.TestCase): + def test_hello(self): + pytest.skip("skip_in_method") + @pytest.mark.skipif("sys.version_info != 1") + def test_hello2(self): + pass + @pytest.mark.xfail(reason="iwanto") + def test_hello3(self): + assert 0 + def test_hello4(self): + pytest.xfail("i2wanto") + + class TC2(unittest.TestCase): + def setup_class(cls): + pytest.skip("skip_in_setup_class") + def test_method(self): + pass + """) + result = testdir.runpytest("-rxs") + assert result.ret == 0 + result.stdout.fnmatch_lines_random([ + "*skip_in_setup_class*", + "*iwanto*", + "*i2wanto*", + "*sys.version_info*", + "*skip_in_method*", + "*3 skipped*2 xfail*", + ]) + + def test_trial_pdb(self, testdir): + p = testdir.makepyfile(""" + from twisted.trial import unittest + import pytest + class TC(unittest.TestCase): + def test_hello(self): + assert 0, "hellopdb" + """) + child = testdir.spawn_pytest(p) + child.expect("hellopdb") + child.sendeof() + +def test_djangolike_testcase(testdir): + # contributed from Morten Breekevold + testdir.makepyfile(""" + from unittest import TestCase, main + + class DjangoLikeTestCase(TestCase): + + def setUp(self): + print ("setUp()") + + def test_presetup_has_been_run(self): + print ("test_thing()") + self.assertTrue(hasattr(self, 'was_presetup')) + + def tearDown(self): + print ("tearDown()") + + def __call__(self, result=None): + try: + self._pre_setup() + except (KeyboardInterrupt, SystemExit): + raise + except Exception: + import sys + result.addError(self, sys.exc_info()) + return + super(DjangoLikeTestCase, self).__call__(result) + try: + self._post_teardown() + except (KeyboardInterrupt, SystemExit): + raise + except Exception: + import sys + result.addError(self, sys.exc_info()) + return + + def _pre_setup(self): + print ("_pre_setup()") + self.was_presetup = True + + def _post_teardown(self): + print ("_post_teardown()") + """) + result = testdir.runpytest("-s") + assert result.ret == 0 + result.stdout.fnmatch_lines([ + "*_pre_setup()*", + "*setUp()*", + "*test_thing()*", + "*tearDown()*", + "*_post_teardown()*", + ]) diff --git a/tox.ini b/tox.ini index 4a7655683..0c20f30f7 100644 --- a/tox.ini +++ b/tox.ini @@ -25,6 +25,13 @@ commands= py.test -n3 -rfsxX \ --junitxml={envlogdir}/junit-{envname}.xml [] +[testenv:trial] +changedir=. +basepython=python2.6 +deps=:pypi:twisted +commands= + py.test -rsxf \ + --junitxml={envlogdir}/junit-{envname}.xml [testing/test_unittest.py] [testenv:doctest] changedir=. commands=py.test --doctest-modules _pytest