Add some custom matchers to make deferred log tests more readable.

This commit is contained in:
Colin Watson
2015-04-04 18:02:48 +01:00
parent e73e7500b7
commit 58787e6258

View File

@@ -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)]