python-testtools/testtools/testresult/doubles.py

234 lines
6.7 KiB
Python

# Copyright (c) 2009-2016 testtools developers. See LICENSE for details.
"""Doubles of test result objects, useful for testing unittest code."""
from collections import namedtuple
from testtools.tags import TagContext
__all__ = [
'Python26TestResult',
'Python27TestResult',
'ExtendedTestResult',
'TwistedTestResult',
'StreamResult',
]
class LoggingBase:
"""Basic support for logging of results."""
def __init__(self, event_log=None):
if event_log is None:
event_log = []
self._events = event_log
class Python26TestResult(LoggingBase):
"""A precisely python 2.6 like test result, that logs."""
def __init__(self, event_log=None):
super().__init__(event_log=event_log)
self.shouldStop = False
self._was_successful = True
self.testsRun = 0
def addError(self, test, err):
self._was_successful = False
self._events.append(('addError', test, err))
def addFailure(self, test, err):
self._was_successful = False
self._events.append(('addFailure', test, err))
def addSuccess(self, test):
self._events.append(('addSuccess', test))
def startTest(self, test):
self._events.append(('startTest', test))
self.testsRun += 1
def stop(self):
self.shouldStop = True
def stopTest(self, test):
self._events.append(('stopTest', test))
def wasSuccessful(self):
return self._was_successful
class Python27TestResult(Python26TestResult):
"""A precisely python 2.7 like test result, that logs."""
def __init__(self, event_log=None):
super().__init__(event_log)
self.failfast = False
def addError(self, test, err):
super().addError(test, err)
if self.failfast:
self.stop()
def addFailure(self, test, err):
super().addFailure(test, err)
if self.failfast:
self.stop()
def addExpectedFailure(self, test, err):
self._events.append(('addExpectedFailure', test, err))
def addSkip(self, test, reason):
self._events.append(('addSkip', test, reason))
def addUnexpectedSuccess(self, test):
self._events.append(('addUnexpectedSuccess', test))
if self.failfast:
self.stop()
def startTestRun(self):
self._events.append(('startTestRun',))
def stopTestRun(self):
self._events.append(('stopTestRun',))
class ExtendedTestResult(Python27TestResult):
"""A test result like the proposed extended unittest result API."""
def __init__(self, event_log=None):
super().__init__(event_log)
self._tags = TagContext()
def addError(self, test, err=None, details=None):
self._was_successful = False
self._events.append(('addError', test, err or details))
def addFailure(self, test, err=None, details=None):
self._was_successful = False
self._events.append(('addFailure', test, err or details))
def addExpectedFailure(self, test, err=None, details=None):
self._events.append(('addExpectedFailure', test, err or details))
def addSkip(self, test, reason=None, details=None):
self._events.append(('addSkip', test, reason or details))
def addSuccess(self, test, details=None):
if details:
self._events.append(('addSuccess', test, details))
else:
self._events.append(('addSuccess', test))
def addUnexpectedSuccess(self, test, details=None):
self._was_successful = False
if details is not None:
self._events.append(('addUnexpectedSuccess', test, details))
else:
self._events.append(('addUnexpectedSuccess', test))
def progress(self, offset, whence):
self._events.append(('progress', offset, whence))
def startTestRun(self):
super().startTestRun()
self._was_successful = True
self._tags = TagContext()
def startTest(self, test):
super().startTest(test)
self._tags = TagContext(self._tags)
def stopTest(self, test):
self._tags = self._tags.parent
super().stopTest(test)
@property
def current_tags(self):
return self._tags.get_current_tags()
def tags(self, new_tags, gone_tags):
self._tags.change_tags(new_tags, gone_tags)
self._events.append(('tags', new_tags, gone_tags))
def time(self, time):
self._events.append(('time', time))
def wasSuccessful(self):
return self._was_successful
class TwistedTestResult(LoggingBase):
"""
Emulate the relevant bits of :py:class:`twisted.trial.itrial.IReporter`.
Used to ensure that we can use ``trial`` as a test runner.
"""
def __init__(self, event_log=None):
super().__init__(event_log=event_log)
self._was_successful = True
self.testsRun = 0
def startTest(self, test):
self.testsRun += 1
self._events.append(('startTest', test))
def stopTest(self, test):
self._events.append(('stopTest', test))
def addSuccess(self, test):
self._events.append(('addSuccess', test))
def addError(self, test, error):
self._was_successful = False
self._events.append(('addError', test, error))
def addFailure(self, test, error):
self._was_successful = False
self._events.append(('addFailure', test, error))
def addExpectedFailure(self, test, failure, todo=None):
self._events.append(('addExpectedFailure', test, failure))
def addUnexpectedSuccess(self, test, todo=None):
self._events.append(('addUnexpectedSuccess', test))
def addSkip(self, test, reason):
self._events.append(('addSkip', test, reason))
def wasSuccessful(self):
return self._was_successful
def done(self):
pass
class StreamResult(LoggingBase):
"""A StreamResult implementation for testing.
All events are logged to _events.
"""
def startTestRun(self):
self._events.append(('startTestRun',))
def stopTestRun(self):
self._events.append(('stopTestRun',))
def status(self, test_id=None, test_status=None, test_tags=None,
runnable=True, file_name=None, file_bytes=None, eof=False,
mime_type=None, route_code=None, timestamp=None):
self._events.append(
_StatusEvent(
'status', test_id, test_status, test_tags, runnable,
file_name, file_bytes, eof, mime_type, route_code,
timestamp))
# Convenience for easier access to status fields
_StatusEvent = namedtuple(
"_Event", [
"name", "test_id", "test_status", "test_tags", "runnable", "file_name",
"file_bytes", "eof", "mime_type", "route_code", "timestamp"])