diff options
| author | Robert Collins <robertc@robertcollins.net> | 2009-07-22 18:11:41 +1000 |
|---|---|---|
| committer | Robert Collins <robertc@robertcollins.net> | 2009-07-22 18:11:41 +1000 |
| commit | 926e1ba475443641089e1146e46462ae4c895d57 (patch) | |
| tree | 213f175a8e0595e7e4bd4077fdc35bda3eb66e0f /python | |
| parent | e3262d627131ae7b68bd2561d3bb270faa53e239 (diff) | |
| download | subunit-git-926e1ba475443641089e1146e46462ae4c895d57.tar.gz | |
Add subunit.test_results.HookedTestResultDecorator.
Diffstat (limited to 'python')
| -rw-r--r-- | python/subunit/test_results.py | 93 | ||||
| -rw-r--r-- | python/subunit/tests/__init__.py | 2 | ||||
| -rw-r--r-- | python/subunit/tests/test_test_results.py | 113 |
3 files changed, 208 insertions, 0 deletions
diff --git a/python/subunit/test_results.py b/python/subunit/test_results.py new file mode 100644 index 0000000..aab86b0 --- /dev/null +++ b/python/subunit/test_results.py @@ -0,0 +1,93 @@ +# +# subunit: extensions to Python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +"""TestResult helper classes used to by subunit.""" + + +class HookedTestResultDecorator(object): + """A TestResult which calls a hook on every event.""" + + def __init__(self, decorated): + self.decorated = decorated + + def _call_maybe(self, method_name, *params): + """Call method_name on self.decorated, if present. + + This is used to guard newer methods which older pythons do not + support. While newer clients won't call these methods if they don't + exist, they do exist on the decorator, and thus the decorator has to be + the one to filter them out. + + :param method_name: The name of the method to call. + :param *params: Parameters to pass to method_name. + :return: The result of self.decorated.method_name(*params), if it + exists, and None otherwise. + """ + method = getattr(self.decorated, method_name, None) + if method is None: + return + return method(*params) + + def startTest(self, test): + self._before_event() + return self.decorated.startTest(test) + + def startTestRun(self): + self._before_event() + return self._call_maybe("startTestRun") + + def stopTest(self, test): + self._before_event() + return self.decorated.stopTest(test) + + def stopTestRun(self): + self._before_event() + return self._call_maybe("stopTestRun") + + def addError(self, test, err): + self._before_event() + return self.decorated.addError(test, err) + + def addFailure(self, test, err): + self._before_event() + return self.decorated.addFailure(test, err) + + def addSuccess(self, test): + self._before_event() + return self.decorated.addSuccess(test) + + def addSkip(self, test, reason): + self._before_event() + return self._call_maybe("addSkip", test, reason) + + def addExpectedFailure(self, test, err): + self._before_event() + return self._call_maybe("addExpectedFailure", test, err) + + def addUnexpectedSuccess(self, test): + self._before_event() + return self._call_maybe("addUnexpectedSuccess", test) + + def wasSuccessful(self): + self._before_event() + return self.decorated.wasSuccessful() + + def stop(self): + self._before_event() + return self.decorated.stop() diff --git a/python/subunit/tests/__init__.py b/python/subunit/tests/__init__.py index fa41930..11f3095 100644 --- a/python/subunit/tests/__init__.py +++ b/python/subunit/tests/__init__.py @@ -24,10 +24,12 @@ from subunit.tests import ( test_subunit_tags, test_tap2subunit, test_test_protocol, + test_test_results, ) def test_suite(): result = TestUtil.TestSuite() + result.addTest(test_test_results.test_suite()) result.addTest(test_test_protocol.test_suite()) result.addTest(test_tap2subunit.test_suite()) result.addTest(test_subunit_filter.test_suite()) diff --git a/python/subunit/tests/test_test_results.py b/python/subunit/tests/test_test_results.py new file mode 100644 index 0000000..a020ba2 --- /dev/null +++ b/python/subunit/tests/test_test_results.py @@ -0,0 +1,113 @@ +# +# subunit: extensions to Python unittest to get test results from subprocesses. +# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +import datetime +import unittest +from StringIO import StringIO +import os +import subunit.test_results +import sys + +import subunit.iso8601 as iso8601 + + +class LoggingDecorator(subunit.test_results.HookedTestResultDecorator): + + def __init__(self, decorated): + self._calls = 0 + super(LoggingDecorator, self).__init__(decorated) + + def _before_event(self): + self._calls += 1 + + +class AssertBeforeTestResult(LoggingDecorator): + """A TestResult for checking preconditions.""" + + def __init__(self, decorated, test): + self.test = test + super(AssertBeforeTestResult, self).__init__(decorated) + + def _before_event(self): + self.test.assertEqual(1, self.earlier._calls) + super(AssertBeforeTestResult, self)._before_event() + + + +class TestHookedTestResultDecorator(unittest.TestCase): + + def setUp(self): + # And end to the chain + terminal = unittest.TestResult() + # Asserts that the call was made to self.result before asserter was + # called. + asserter = AssertBeforeTestResult(terminal, self) + # The result object we call, which much increase its call count. + self.result = LoggingDecorator(asserter) + asserter.earlier = self.result + + def tearDown(self): + # The hook in self.result must have been called + self.assertEqual(1, self.result._calls) + # The hook in asserter must have been called too, otherwise the + # assertion about ordering won't have completed. + self.assertEqual(1, self.result.decorated._calls) + + def test_startTest(self): + self.result.startTest(self) + + def test_startTestRun(self): + self.result.startTestRun() + + def test_stopTest(self): + self.result.stopTest(self) + + def test_stopTestRun(self): + self.result.stopTestRun() + + def test_addError(self): + self.result.addError(self, subunit.RemoteError()) + + def test_addFailure(self): + self.result.addFailure(self, subunit.RemoteError()) + + def test_addSuccess(self): + self.result.addSuccess(self) + + def test_addSkip(self): + self.result.addSkip(self, "foo") + + def test_addExpectedFailure(self): + self.result.addExpectedFailure(self, subunit.RemoteError()) + + def test_addUnexpectedSuccess(self): + self.result.addUnexpectedSuccess(self) + + def test_wasSuccessful(self): + self.result.wasSuccessful() + + def test_stop(self): + self.result.stop() + + + +def test_suite(): + loader = subunit.tests.TestUtil.TestLoader() + result = loader.loadTestsFromName(__name__) + return result |
