2
# subunit: extensions to Python unittest to get test results from subprocesses.
3
# Copyright (C) 2009 Robert Collins <robertc@robertcollins.net>
5
# Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
6
# license at the users choice. A copy of both licenses are available in the
7
# project source as Apache-2.0 and BSD. You may not use this file except in
8
# compliance with one of these two licences.
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# license you chose for the specific language governing permissions and
14
# limitations under that license.
20
from testtools import TestCase
21
from testtools.testresult.doubles import ExtendedTestResult
24
import subunit.iso8601 as iso8601
25
import subunit.test_results
28
class LoggingDecorator(subunit.test_results.HookedTestResultDecorator):
30
def __init__(self, decorated):
32
super(LoggingDecorator, self).__init__(decorated)
34
def _before_event(self):
38
class AssertBeforeTestResult(LoggingDecorator):
39
"""A TestResult for checking preconditions."""
41
def __init__(self, decorated, test):
43
super(AssertBeforeTestResult, self).__init__(decorated)
45
def _before_event(self):
46
self.test.assertEqual(1, self.earlier._calls)
47
super(AssertBeforeTestResult, self)._before_event()
50
class TimeCapturingResult(unittest.TestResult):
53
super(TimeCapturingResult, self).__init__()
56
def time(self, a_datetime):
57
self._calls.append(a_datetime)
60
class TestHookedTestResultDecorator(unittest.TestCase):
64
terminal = unittest.TestResult()
65
# Asserts that the call was made to self.result before asserter was
67
asserter = AssertBeforeTestResult(terminal, self)
68
# The result object we call, which much increase its call count.
69
self.result = LoggingDecorator(asserter)
70
asserter.earlier = self.result
71
self.decorated = asserter
74
# The hook in self.result must have been called
75
self.assertEqual(1, self.result._calls)
76
# The hook in asserter must have been called too, otherwise the
77
# assertion about ordering won't have completed.
78
self.assertEqual(1, self.decorated._calls)
80
def test_startTest(self):
81
self.result.startTest(self)
83
def test_startTestRun(self):
84
self.result.startTestRun()
86
def test_stopTest(self):
87
self.result.stopTest(self)
89
def test_stopTestRun(self):
90
self.result.stopTestRun()
92
def test_addError(self):
93
self.result.addError(self, subunit.RemoteError())
95
def test_addError_details(self):
96
self.result.addError(self, details={})
98
def test_addFailure(self):
99
self.result.addFailure(self, subunit.RemoteError())
101
def test_addFailure_details(self):
102
self.result.addFailure(self, details={})
104
def test_addSuccess(self):
105
self.result.addSuccess(self)
107
def test_addSuccess_details(self):
108
self.result.addSuccess(self, details={})
110
def test_addSkip(self):
111
self.result.addSkip(self, "foo")
113
def test_addSkip_details(self):
114
self.result.addSkip(self, details={})
116
def test_addExpectedFailure(self):
117
self.result.addExpectedFailure(self, subunit.RemoteError())
119
def test_addExpectedFailure_details(self):
120
self.result.addExpectedFailure(self, details={})
122
def test_addUnexpectedSuccess(self):
123
self.result.addUnexpectedSuccess(self)
125
def test_addUnexpectedSuccess_details(self):
126
self.result.addUnexpectedSuccess(self, details={})
128
def test_progress(self):
129
self.result.progress(1, subunit.PROGRESS_SET)
131
def test_wasSuccessful(self):
132
self.result.wasSuccessful()
134
def test_shouldStop(self):
135
self.result.shouldStop
141
self.result.time(None)
144
class TestAutoTimingTestResultDecorator(unittest.TestCase):
147
# And end to the chain which captures time events.
148
terminal = TimeCapturingResult()
149
# The result object under test.
150
self.result = subunit.test_results.AutoTimingTestResultDecorator(
152
self.decorated = terminal
154
def test_without_time_calls_time_is_called_and_not_None(self):
155
self.result.startTest(self)
156
self.assertEqual(1, len(self.decorated._calls))
157
self.assertNotEqual(None, self.decorated._calls[0])
159
def test_no_time_from_progress(self):
160
self.result.progress(1, subunit.PROGRESS_CUR)
161
self.assertEqual(0, len(self.decorated._calls))
163
def test_no_time_from_shouldStop(self):
164
self.decorated.stop()
165
self.result.shouldStop
166
self.assertEqual(0, len(self.decorated._calls))
168
def test_calling_time_inhibits_automatic_time(self):
169
# Calling time() outputs a time signal immediately and prevents
170
# automatically adding one when other methods are called.
171
time = datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc())
172
self.result.time(time)
173
self.result.startTest(self)
174
self.result.stopTest(self)
175
self.assertEqual(1, len(self.decorated._calls))
176
self.assertEqual(time, self.decorated._calls[0])
178
def test_calling_time_None_enables_automatic_time(self):
179
time = datetime.datetime(2009,10,11,12,13,14,15, iso8601.Utc())
180
self.result.time(time)
181
self.assertEqual(1, len(self.decorated._calls))
182
self.assertEqual(time, self.decorated._calls[0])
183
# Calling None passes the None through, in case other results care.
184
self.result.time(None)
185
self.assertEqual(2, len(self.decorated._calls))
186
self.assertEqual(None, self.decorated._calls[1])
187
# Calling other methods doesn't generate an automatic time event.
188
self.result.startTest(self)
189
self.assertEqual(3, len(self.decorated._calls))
190
self.assertNotEqual(None, self.decorated._calls[2])
193
class TestTagCollapsingDecorator(TestCase):
195
def test_tags_forwarded_outside_of_tests(self):
196
result = ExtendedTestResult()
197
tag_collapser = subunit.test_results.TagCollapsingDecorator(result)
198
tag_collapser.tags(set(['a', 'b']), set())
200
[('tags', set(['a', 'b']), set([]))], result._events)
202
def test_tags_collapsed_inside_of_tests(self):
203
result = ExtendedTestResult()
204
tag_collapser = subunit.test_results.TagCollapsingDecorator(result)
205
test = subunit.RemotedTestCase('foo')
206
tag_collapser.startTest(test)
207
tag_collapser.tags(set(['a']), set())
208
tag_collapser.tags(set(['b']), set(['a']))
209
tag_collapser.tags(set(['c']), set())
210
tag_collapser.stopTest(test)
212
[('startTest', test),
213
('tags', set(['b', 'c']), set(['a'])),
217
def test_tags_collapsed_inside_of_tests_different_ordering(self):
218
result = ExtendedTestResult()
219
tag_collapser = subunit.test_results.TagCollapsingDecorator(result)
220
test = subunit.RemotedTestCase('foo')
221
tag_collapser.startTest(test)
222
tag_collapser.tags(set(), set(['a']))
223
tag_collapser.tags(set(['a', 'b']), set())
224
tag_collapser.tags(set(['c']), set())
225
tag_collapser.stopTest(test)
227
[('startTest', test),
228
('tags', set(['a', 'b', 'c']), set()),
233
class TestTimeCollapsingDecorator(TestCase):
237
return datetime.datetime(
238
2000, 1, self.getUniqueInteger(), tzinfo=iso8601.UTC)
240
def test_initial_time_forwarded(self):
241
# We always forward the first time event we see.
242
result = ExtendedTestResult()
243
tag_collapser = subunit.test_results.TimeCollapsingDecorator(result)
244
a_time = self.make_time()
245
tag_collapser.time(a_time)
246
self.assertEquals([('time', a_time)], result._events)
248
def test_time_collapsed_to_first_and_last(self):
249
# If there are many consecutive time events, only the first and last
251
result = ExtendedTestResult()
252
tag_collapser = subunit.test_results.TimeCollapsingDecorator(result)
253
times = [self.make_time() for i in range(5)]
255
tag_collapser.time(a_time)
256
tag_collapser.startTest(subunit.RemotedTestCase('foo'))
258
[('time', times[0]), ('time', times[-1])], result._events[:-1])
260
def test_only_one_time_sent(self):
261
# If we receive a single time event followed by a non-time event, we
262
# send exactly one time event.
263
result = ExtendedTestResult()
264
tag_collapser = subunit.test_results.TimeCollapsingDecorator(result)
265
a_time = self.make_time()
266
tag_collapser.time(a_time)
267
tag_collapser.startTest(subunit.RemotedTestCase('foo'))
268
self.assertEquals([('time', a_time)], result._events[:-1])
270
def test_duplicate_times_not_sent(self):
271
# Many time events with the exact same time are collapsed into one
273
result = ExtendedTestResult()
274
tag_collapser = subunit.test_results.TimeCollapsingDecorator(result)
275
a_time = self.make_time()
277
tag_collapser.time(a_time)
278
tag_collapser.startTest(subunit.RemotedTestCase('foo'))
279
self.assertEquals([('time', a_time)], result._events[:-1])
281
def test_no_times_inserted(self):
282
result = ExtendedTestResult()
283
tag_collapser = subunit.test_results.TimeCollapsingDecorator(result)
284
a_time = self.make_time()
285
tag_collapser.time(a_time)
286
foo = subunit.RemotedTestCase('foo')
287
tag_collapser.startTest(foo)
288
tag_collapser.addSuccess(foo)
289
tag_collapser.stopTest(foo)
294
('stopTest', foo)], result._events)
298
loader = subunit.tests.TestUtil.TestLoader()
299
result = loader.loadTestsFromName(__name__)