""" Format unittest results in Test Anything Protocol (TAP). http://testanything.org/tap-version-13-specification.html Public domain work by: anatoly techtonik Changes: 0.3 - fixed used imports that failed on Python 2.6 0.2 - removed unused import that failed on Python 2.6 0.1 - initial release """ __version__ = "0.3" from unittest import TextTestRunner try: from unittest import TextTestResult except ImportError: # Python 2.6 from unittest import _TextTestResult as TextTestResult class TAPTestResult(TextTestResult): def _process(self, test, msg, failtype = None, directive = None): """ increase the counter, format and output TAP info """ # counterhack: increase test counter test.suite.tap_counter += 1 msg = "%s %d" % (msg, test.suite.tap_counter) if "not" not in msg: msg += " " # justify self.stream.write("%s - " % msg) if failtype: self.stream.write("%s - " % failtype) self.stream.write("%s" % test.__class__.__name__) self.stream.write(".%s" % test._testMethodName) if directive: self.stream.write(directive) self.stream.write("\n") # [ ] write test __doc__ (if exists) in comment self.stream.flush() def addSuccess(self, test): super(TextTestResult, self).addSuccess(test) self._process(test, "ok") def addFailure(self, test, err): super(TextTestResult, self).addFailure(test, err) self._process(test, "not ok", "FAIL") # [ ] add structured data about assertion def addError(self, test, err): super(TextTestResult, self).addError(test, err) self._process(test, "not ok", "ERROR") # [ ] add structured data about exception def addSkip(self, test, reason): super(TextTestResult, self).addSkip(test, reason) self._process(test, "ok", directive=(" # SKIP %s" % reason)) def addExpectedFailure(self, test, err): super(TextTestResult, self).addExpectedFailure(test, err) self._process(test, "not ok", directive=(" # TODO")) def addUnexpectedSuccess(self, test): super(TextTestResult, self).addUnexpectedSuccess(test) self._process(test, "not ok", "FAIL (unexpected success)") """ def printErrors(self): def printErrorList(self, flavour, errors): """ class TAPTestRunner(TextTestRunner): resultclass = TAPTestResult def run(self, test): self.stream.write("TAP version 13\n") # [ ] add commented block with test suite __doc__ # [ ] check call with a single test # if isinstance(test, suite.TestSuite): self.stream.write("1..%s\n" % len(list(test))) # counterhack: inject test counter into test suite test.tap_counter = 0 # counterhack: inject reference to suite into each test case for case in test: case.suite = test return super(TAPTestRunner, self).run(test) if __name__ == "__main__": import sys import unittest class Test(unittest.TestCase): def test_ok(self): pass def test_fail(self): self.assertTrue(False) def test_error(self): bad_symbol @unittest.skip("skipin'") def test_skip(self): pass @unittest.expectedFailure def test_not_ready(self): self.fail() @unittest.expectedFailure def test_invalid_fail_mark(self): pass def test_another_ok(self): pass suite = unittest.TestSuite([ Test('test_ok'), Test('test_fail'), Test('test_error'), Test('test_skip'), Test('test_not_ready'), Test('test_invalid_fail_mark'), Test('test_another_ok') ]) if not TAPTestRunner().run(suite).wasSuccessful(): sys.exit(1)