Michael Foord avatar Michael Foord committed d34125d

TextTestRunner uses the new reports for generating its summary at the end
Adding back the add* methods to TextTestResult
Changed result.wasSuccessful to use the new reports
Changed the junit-xml to not crash if ElementTree is not available
Added setOutcome method and standardOutcome to StopTestEvent

Comments (0)

Files changed (6)

 
 [junit-xml]
 always-on = False
-#path = '~/report.xml'
+path = junit.xml
 
 [timed]
 always-on = True

unittest2/events.py

 
         self.metadata = {}
         
-        self.outcome = None
+
+        # class, setUp, call, tearDown, cleanUp
+        # or None for a pass
+        self.stage = stage
+        self.setOutcome(outcome)
+
+    def setOutcome(self, outcome, standardOutcome=None, shortResult=None,
+                   longResult=None, skipReason=''):
+        if standardOutcome is None:
+            standardOutcome = outcome
+            longResult, shortResult = _DEFAULT_RESULTS[outcome]
+            if outcome == 'skipped':
+                skipReason = str(self.exc_info[1])
+
+        self.outcome = outcome
+        self.standardOutome = standardOutcome
+
+        self.shortResult = shortResult
+        self.longResult = longResult
+
         self.passed = False
         self.failed = False
         self.error = False
         self.unexpectedSuccess = False
         self.expectedFailure = False
 
-        # class, setUp, call, tearDown, cleanUp
-        # or None for a pass
-        self.stage = stage
-        self.outcome = outcome
-
-        longResult, shortResult = _DEFAULT_RESULTS[outcome]
-        self.shortResult = shortResult
-        self.longResult = longResult
-
-        if outcome == 'passed':
+        if standardOutcome == 'passed':
             self.passed = True
-        elif outcome == 'failed':
+        elif standardOutcome == 'failed':
             self.failed = True
-        elif outcome == 'error':
+        elif standardOutcome == 'error':
             self.error = True
-        elif outcome == 'skipped':
+        elif standardOutcome == 'skipped':
             self.skipped = True
-            self.skipReason = str(self.exc_info[1])
+            self.skipReason = skipReason
             self.longResult = longResult % self.skipReason
-        elif outcome == 'unexpectedSuccess':
+        elif standardOutcome == 'unexpectedSuccess':
             self.unexpectedSuccess = True
-        elif outcome == 'expectedFailure':
+        elif standardOutcome == 'expectedFailure':
             self.expectedFailure = True
+        else:
+            msg = ('standardOutcome must map to a standard outcome: %r' %
+                   (standardOutcome,))
+            raise ValueError(msg)
 
 
 class PluginsLoadedEvent(_Event):

unittest2/plugins/counttests.py

         self.skipped = set()
         self.unexpectedSuccess = set()
         self.expectedFailure = set()
+        self.other = set()
         self.seen = {}
 
         self.enhanced = self.config.as_bool('enhanced', False)
             self.seen[test_id].remove(test_id)
             del self.seen[test_id]
         
-        the_set = getattr(self, event.outcome)
+        the_set = getattr(self, event.outcome, self.other)
         the_set.add(test_id)
         self.seen[test_id] = the_set
 
         values = []
         frag = '%s%s'
         for letter, attr in [('s', 'skipped'), ('f', 'failed'), ('e', 'error'),
-                             ('u', 'unexpectedSuccess'),
+                             ('u', 'unexpectedSuccess'), ('o', 'other'),
                              ('x', 'expectedFailure'), ('p', 'passed')]:
             number = len(getattr(self, attr))
             if not number and attr != 'passed':

unittest2/plugins/junitxml.py

     http://codespeak.net/py/dist/test/plugin/junitxml.html
 
 """
-
-from xml.etree import ElementTree as ET
-
-from unittest2.events import Plugin, addOption
+try:
+    from xml.etree import ElementTree as ET
+except ImportError:
+    try:
+        import ElementTree as ET
+    except ImportError:
+        ET = None
+    
+from unittest2.events import Plugin
 
 class JunitXml(Plugin):
 
         self.failed = 0
         self.skipped = 0
         self.numtests = 0
-        self.tree = ET.Element('testsuite')
+        if ET is not None:
+            self.tree = ET.Element('testsuite')
+
+    def pluginsLoaded(self):
+        if ET is None:
+            raise ImportError('junit-xml plugin requires ElementTree')
 
     def startTest(self, event):
         self.numtests += 1

unittest2/result.py

         See startTest for a method called before each test.
         """
     
-    @failfast
     def addReport(self, report):
         self.reports.append(report)
 
         err = report.exc_info
         reason = report.skipReason
 
-        if report.passed:
-            # call directly on this class instead?
+        if report.outcome == 'passed':
             self.addSuccess(test)
-        elif report.failed:
+        elif report.outcome == 'failed':
             self.addFailure(test, err)
-        elif report.error:
+        elif report.outcome == 'error':
             self.addError(test, err)
-        elif report.skipped:
+        elif report.outcome == 'skipped':
             self.addSkip(test, reason)
-        elif report.unexpectedSuccess:
+        elif report.outcome == 'unexpectedSuccess':
             self.addUnexpectedSuccess(test)
-        elif report.expectedFailure:
+        elif report.outcome == 'expectedFailure':
             self.addExpectedFailure(test, err)
 
     def stopTest(self, test):
 
     def wasSuccessful(self):
         "Tells whether or not this result was a success"
-        return (len(self.failures) + len(self.errors) == 0)
+        return (len([True for report in self.reports
+                    if report.outcome in ('error', 'failed') ]) == 0 and
+                len(self.errors) + len(self.failures) == 0)
 
     def stop(self):
         "Indicates that the tests should be aborted"

unittest2/runner.py

 
     def __init__(self, stream, descriptions, verbosity):
         super(TextTestResult, self).__init__()
+        self._reported = False
         self.stream = stream
         self.showAll = verbosity > 1
         self.dots = verbosity == 1
         self.descriptions = descriptions
+        self.reportCategories = {}
 
     def getDescription(self, test):
         doc_first_line = test.shortDescription()
             return str(test)
     
     def addReport(self, report):
+        self._reported = False
         super(TextTestResult, self).addReport(report)
+        if self._reported:
+            return
         if self.showAll:
             self.stream.writeln(report.longResult)
         elif self.dots:
             self.stream.flush()
 
     def startTest(self, test):
+        self._reported = True
         super(TextTestResult, self).startTest(test)
         if self.showAll:
             self.stream.write(self.getDescription(test))
             self.stream.write(" ... ")
             self.stream.flush()
 
+    def addSuccess(self, test):
+        super(TextTestResult, self).addSuccess(test)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("ok")
+        elif self.dots:
+            self.stream.write('.')
+            self.stream.flush()
+
+    def addError(self, test, err):
+        super(TextTestResult, self).addError(test, err)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("ERROR")
+        elif self.dots:
+            self.stream.write('E')
+            self.stream.flush()
+
+    def addFailure(self, test, err):
+        super(TextTestResult, self).addFailure(test, err)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("FAIL")
+        elif self.dots:
+            self.stream.write('F')
+            self.stream.flush()
+
+    def addSkip(self, test, reason):
+        super(TextTestResult, self).addSkip(test, reason)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("skipped %r" % reason)
+        elif self.dots:
+            self.stream.write("s")
+            self.stream.flush()
+
+    def addExpectedFailure(self, test, err):
+        super(TextTestResult, self).addExpectedFailure(test, err)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("expected failure")
+        elif self.dots:
+            self.stream.write("x")
+            self.stream.flush()
+
+    def addUnexpectedSuccess(self, test):
+        super(TextTestResult, self).addUnexpectedSuccess(test)
+        self._reported = True
+        if self.showAll:
+            self.stream.writeln("unexpected success")
+        elif self.dots:
+            self.stream.write("u")
+            self.stream.flush()
+
     def printErrors(self):
         if self.dots or self.showAll:
             self.stream.writeln()
 
-        reportsCategories = {}
         for report in self.reports:
-            reportList = reportsCategories.setdefault(report.outcome, [])
+            reportList = self.reportCategories.setdefault(report.outcome, [])
             reportList.append((report.description, report.traceback))
         
-        errors = reportsCategories.pop('passed', [])
-        failures = reportsCategories.pop('failed', [])
-        reportsCategories.pop('skipped', None)
-        reportsCategories.pop('ok', None)
-        reportsCategories.pop('expectedFailures', None)
-        reportsCategories.pop('unexpectedSuccess', None)
-
+        errors = self.reportCategories.get('error', [])
+        failures = self.reportCategories.get('failed', [])
         self.printErrorList('ERROR', self.errors)
         self.printErrorList('FAIL', self.failures)
-        
-        for flavour, results in reportsCategories.items():
+
+        dontReport = set(['error', 'failed', 'skipped', 'passed',
+                          'expectedFailures', 'unexpectedSuccess'])
+        for flavour, results in self.reportCategories.items():
+            if flavour in dontReport:
+                continue
             self.printErrorList(flavour.upper(), results)
 
     def printErrorList(self, flavour, errors):
                             (run, run != 1 and "s" or "", timeTaken))
         self.message(msg, (0, 1, 2))
         
-        expectedFails = unexpectedSuccesses = skipped = 0
-        try:
-            results = map(len, (result.expectedFailures,
-                                result.unexpectedSuccesses,
-                                result.skipped))
-            expectedFails, unexpectedSuccesses, skipped = results
-        except AttributeError:
-            pass
         infos = []
-        if not result.wasSuccessful():
+        extraInfos = []
+        if result.wasSuccessful():
+            self.message("OK", (0, 1, 2))
+        else:
             self.message("FAILED", (0, 1, 2))
+
+        if not hasattr(result, 'reportCategories'):
+            expectedFails = unexpectedSuccesses = skipped = 0
+            try:
+                results = map(len, (result.expectedFailures,
+                                    result.unexpectedSuccesses,
+                                    result.skipped))
+                expectedFails, unexpectedSuccesses, skipped = results
+            except AttributeError:
+                pass
             failed, errored = map(len, (result.failures, result.errors))
-            if failed:
-                infos.append("failures=%d" % failed)
-            if errored:
-                infos.append("errors=%d" % errored)
         else:
-            self.message("OK", (0, 1, 2))
+            failed = len(result.reportCategories.get('failed', []))
+            errored = len(result.reportCategories.get('error', []))
+            skipped = len(result.reportCategories.get('skipped', []))
+            expectedFails = len(result.reportCategories.get('expectedFails', []))
+            unexpectedSuccesses = len(result.reportCategories.get('unexpectedSuccesses', []))
+            
+            dontReport = set(['error', 'failed', 'skipped', 'passed',
+                              'expectedFailures', 'unexpectedSuccess'])
+            for flavour, results in result.reportCategories.items():
+                if flavour in dontReport:
+                    continue
+                extraInfos.append("%s=%d" % (flavour, len(results)))
+
+        if failed:
+            infos.append("failures=%d" % failed)
+        if errored:
+            infos.append("errors=%d" % errored)
         if skipped:
             infos.append("skipped=%d" % skipped)
         if expectedFails:
             infos.append("expected failures=%d" % expectedFails)
         if unexpectedSuccesses:
             infos.append("unexpected successes=%d" % unexpectedSuccesses)
+        infos.extend(extraInfos)
         if infos:
             self.message(" (%s)" % (", ".join(infos),), (0, 1, 2))
-
         self.message("\n")
         return result
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.