Add some custom matchers to make deferred log tests more readable.
This commit is contained in:
@@ -12,15 +12,17 @@ from testtools import (
|
||||
TestCase,
|
||||
TestResult,
|
||||
)
|
||||
from testtools.content import (
|
||||
text_content,
|
||||
)
|
||||
from testtools.matchers import (
|
||||
AfterPreprocessing,
|
||||
ContainsAll,
|
||||
EndsWith,
|
||||
Equals,
|
||||
Is,
|
||||
KeysEqual,
|
||||
MatchesDict,
|
||||
MatchesException,
|
||||
MatchesListwise,
|
||||
Not,
|
||||
Raises,
|
||||
)
|
||||
from testtools.runtest import RunTest
|
||||
@@ -41,6 +43,45 @@ log = try_import('twisted.python.log')
|
||||
DelayedCall = try_import('twisted.internet.base.DelayedCall')
|
||||
|
||||
|
||||
class MatchesEvents(object):
|
||||
"""Match a list of test result events.
|
||||
|
||||
Specify events as a data structure. Ordinary Python objects within this
|
||||
structure will be compared exactly, but you can also use matchers at any
|
||||
point.
|
||||
"""
|
||||
|
||||
def __init__(self, *expected):
|
||||
self._expected = expected
|
||||
|
||||
def _make_matcher(self, obj):
|
||||
# This isn't very safe for general use, but is good enough to make
|
||||
# some tests in this module more readable.
|
||||
if hasattr(obj, 'match'):
|
||||
return obj
|
||||
elif isinstance(obj, tuple) or isinstance(obj, list):
|
||||
return MatchesListwise(
|
||||
[self._make_matcher(item) for item in obj])
|
||||
elif isinstance(obj, dict):
|
||||
return MatchesDict(dict(
|
||||
(key, self._make_matcher(value))
|
||||
for key, value in obj.items()))
|
||||
else:
|
||||
return Equals(obj)
|
||||
|
||||
def match(self, observed):
|
||||
matcher = self._make_matcher(self._expected)
|
||||
return matcher.match(observed)
|
||||
|
||||
|
||||
class AsText(AfterPreprocessing):
|
||||
"""Match the text of a Content instance."""
|
||||
|
||||
def __init__(self, matcher, annotate=True):
|
||||
super(AsText, self).__init__(
|
||||
lambda log: log.as_text(), matcher, annotate=annotate)
|
||||
|
||||
|
||||
class X(object):
|
||||
"""Tests that we run as part of our tests, nested to avoid discovery."""
|
||||
|
||||
@@ -598,13 +639,20 @@ class TestAsynchronousDeferredRunTest(NeedsTwistedTestCase):
|
||||
result = self.make_result()
|
||||
runner.run(result)
|
||||
self.assertThat(
|
||||
[event[:2] for event in result._events],
|
||||
Equals([
|
||||
result._events,
|
||||
MatchesEvents(
|
||||
('startTest', test),
|
||||
('addError', test),
|
||||
('stopTest', test)]))
|
||||
error = result._events[1][2]
|
||||
self.assertThat(error, KeysEqual('logged-error', 'twisted-log'))
|
||||
('addError', test, {
|
||||
'logged-error': AsText(ContainsAll([
|
||||
'Traceback (most recent call last):',
|
||||
'ZeroDivisionError',
|
||||
])),
|
||||
'twisted-log': AsText(ContainsAll([
|
||||
'Traceback (most recent call last):',
|
||||
'ZeroDivisionError',
|
||||
])),
|
||||
}),
|
||||
('stopTest', test)))
|
||||
|
||||
def test_log_err_flushed_is_success(self):
|
||||
# An error logged during the test run is recorded as an error in the
|
||||
@@ -622,17 +670,16 @@ class TestAsynchronousDeferredRunTest(NeedsTwistedTestCase):
|
||||
result = self.make_result()
|
||||
runner.run(result)
|
||||
self.assertThat(
|
||||
[event[:2] for event in result._events],
|
||||
Equals([
|
||||
result._events,
|
||||
MatchesEvents(
|
||||
('startTest', test),
|
||||
('addSuccess', test),
|
||||
('stopTest', test)]))
|
||||
error = result._events[1][2]
|
||||
self.assertThat(error, KeysEqual('twisted-log'))
|
||||
self.assertThat(
|
||||
error['twisted-log'].as_text(),
|
||||
ContainsAll(
|
||||
['Traceback (most recent call last):', 'ZeroDivisionError']))
|
||||
('addSuccess', test, {
|
||||
'twisted-log': AsText(ContainsAll([
|
||||
'Traceback (most recent call last):',
|
||||
'ZeroDivisionError',
|
||||
])),
|
||||
}),
|
||||
('stopTest', test)))
|
||||
|
||||
def test_log_in_details(self):
|
||||
class LogAnError(TestCase):
|
||||
@@ -644,14 +691,14 @@ class TestAsynchronousDeferredRunTest(NeedsTwistedTestCase):
|
||||
result = self.make_result()
|
||||
runner.run(result)
|
||||
self.assertThat(
|
||||
[event[:2] for event in result._events],
|
||||
Equals([
|
||||
result._events,
|
||||
MatchesEvents(
|
||||
('startTest', test),
|
||||
('addError', test),
|
||||
('stopTest', test)]))
|
||||
error = result._events[1][2]
|
||||
self.assertThat(error, KeysEqual('traceback', 'twisted-log'))
|
||||
self.assertThat(error['twisted-log'].as_text(), EndsWith(' foo\n'))
|
||||
('addError', test, {
|
||||
'traceback': Not(Is(None)),
|
||||
'twisted-log': AsText(EndsWith(' foo\n')),
|
||||
}),
|
||||
('stopTest', test)))
|
||||
|
||||
def test_debugging_unchanged_during_test_by_default(self):
|
||||
debugging = [(defer.Deferred.debug, DelayedCall.debug)]
|
||||
|
||||
Reference in New Issue
Block a user