Add some custom matchers to make deferred log tests more readable.
This commit is contained in:
@@ -12,15 +12,17 @@ from testtools import (
|
|||||||
TestCase,
|
TestCase,
|
||||||
TestResult,
|
TestResult,
|
||||||
)
|
)
|
||||||
from testtools.content import (
|
|
||||||
text_content,
|
|
||||||
)
|
|
||||||
from testtools.matchers import (
|
from testtools.matchers import (
|
||||||
|
AfterPreprocessing,
|
||||||
ContainsAll,
|
ContainsAll,
|
||||||
EndsWith,
|
EndsWith,
|
||||||
Equals,
|
Equals,
|
||||||
|
Is,
|
||||||
KeysEqual,
|
KeysEqual,
|
||||||
|
MatchesDict,
|
||||||
MatchesException,
|
MatchesException,
|
||||||
|
MatchesListwise,
|
||||||
|
Not,
|
||||||
Raises,
|
Raises,
|
||||||
)
|
)
|
||||||
from testtools.runtest import RunTest
|
from testtools.runtest import RunTest
|
||||||
@@ -41,6 +43,45 @@ log = try_import('twisted.python.log')
|
|||||||
DelayedCall = try_import('twisted.internet.base.DelayedCall')
|
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):
|
class X(object):
|
||||||
"""Tests that we run as part of our tests, nested to avoid discovery."""
|
"""Tests that we run as part of our tests, nested to avoid discovery."""
|
||||||
|
|
||||||
@@ -598,13 +639,20 @@ class TestAsynchronousDeferredRunTest(NeedsTwistedTestCase):
|
|||||||
result = self.make_result()
|
result = self.make_result()
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
[event[:2] for event in result._events],
|
result._events,
|
||||||
Equals([
|
MatchesEvents(
|
||||||
('startTest', test),
|
('startTest', test),
|
||||||
('addError', test),
|
('addError', test, {
|
||||||
('stopTest', test)]))
|
'logged-error': AsText(ContainsAll([
|
||||||
error = result._events[1][2]
|
'Traceback (most recent call last):',
|
||||||
self.assertThat(error, KeysEqual('logged-error', 'twisted-log'))
|
'ZeroDivisionError',
|
||||||
|
])),
|
||||||
|
'twisted-log': AsText(ContainsAll([
|
||||||
|
'Traceback (most recent call last):',
|
||||||
|
'ZeroDivisionError',
|
||||||
|
])),
|
||||||
|
}),
|
||||||
|
('stopTest', test)))
|
||||||
|
|
||||||
def test_log_err_flushed_is_success(self):
|
def test_log_err_flushed_is_success(self):
|
||||||
# An error logged during the test run is recorded as an error in the
|
# 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()
|
result = self.make_result()
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
[event[:2] for event in result._events],
|
result._events,
|
||||||
Equals([
|
MatchesEvents(
|
||||||
('startTest', test),
|
('startTest', test),
|
||||||
('addSuccess', test),
|
('addSuccess', test, {
|
||||||
('stopTest', test)]))
|
'twisted-log': AsText(ContainsAll([
|
||||||
error = result._events[1][2]
|
'Traceback (most recent call last):',
|
||||||
self.assertThat(error, KeysEqual('twisted-log'))
|
'ZeroDivisionError',
|
||||||
self.assertThat(
|
])),
|
||||||
error['twisted-log'].as_text(),
|
}),
|
||||||
ContainsAll(
|
('stopTest', test)))
|
||||||
['Traceback (most recent call last):', 'ZeroDivisionError']))
|
|
||||||
|
|
||||||
def test_log_in_details(self):
|
def test_log_in_details(self):
|
||||||
class LogAnError(TestCase):
|
class LogAnError(TestCase):
|
||||||
@@ -644,14 +691,14 @@ class TestAsynchronousDeferredRunTest(NeedsTwistedTestCase):
|
|||||||
result = self.make_result()
|
result = self.make_result()
|
||||||
runner.run(result)
|
runner.run(result)
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
[event[:2] for event in result._events],
|
result._events,
|
||||||
Equals([
|
MatchesEvents(
|
||||||
('startTest', test),
|
('startTest', test),
|
||||||
('addError', test),
|
('addError', test, {
|
||||||
('stopTest', test)]))
|
'traceback': Not(Is(None)),
|
||||||
error = result._events[1][2]
|
'twisted-log': AsText(EndsWith(' foo\n')),
|
||||||
self.assertThat(error, KeysEqual('traceback', 'twisted-log'))
|
}),
|
||||||
self.assertThat(error['twisted-log'].as_text(), EndsWith(' foo\n'))
|
('stopTest', test)))
|
||||||
|
|
||||||
def test_debugging_unchanged_during_test_by_default(self):
|
def test_debugging_unchanged_during_test_by_default(self):
|
||||||
debugging = [(defer.Deferred.debug, DelayedCall.debug)]
|
debugging = [(defer.Deferred.debug, DelayedCall.debug)]
|
||||||
|
|||||||
Reference in New Issue
Block a user