Merge lp:~lifeless/testtools/bug-683332 into lp:~testtools-committers/testtools/trunk

Proposed by Robert Collins
Status: Merged
Merged at revision: 150
Proposed branch: lp:~lifeless/testtools/bug-683332
Merge into: lp:~testtools-committers/testtools/trunk
Diff against target: 210 lines (+46/-25)
3 files modified
NEWS (+10/-2)
testtools/testresult/real.py (+12/-15)
testtools/tests/test_testresult.py (+24/-8)
To merge this branch: bzr merge lp:~lifeless/testtools/bug-683332
Reviewer Review Type Date Requested Status
Jelmer Vernooij code Approve
testtools developers Pending
Review via email: mp+42751@code.launchpad.net

Description of the change

Fix bug. Yay.

To post a comment you must log in.
Revision history for this message
Jelmer Vernooij (jelmer) :
review: Approve (code)
Revision history for this message
Robert Collins (lifeless) wrote :

Landing this as a timeout.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2010-11-29 23:46:10 +0000
3+++ NEWS 2010-12-04 21:08:52 +0000
4@@ -10,10 +10,18 @@
5 * addUnexpectedSuccess is translated to addFailure for test results that don't
6 know about addUnexpectedSuccess. Further, it fails the entire result for
7 all testtools TestResults (i.e. wasSuccessful() returns False after
8- addUnexpectedSuccess has been called). (Jonathan Lange, #654474)
9+ addUnexpectedSuccess has been called). Note that when using a delegating
10+ result such as ThreadsafeForwardingResult, MultiTestResult or
11+ ExtendedToOriginalDecorator then the behaviour of addUnexpectedSuccess is
12+ determined by the delegated to result(s).
13+ (Jonathan Lange, Robert Collins, #654474, #683332)
14
15 * startTestRun will reset any errors on the result. That is, wasSuccessful()
16- will always return True immediately after startTestRun() is called.
17+ will always return True immediately after startTestRun() is called. This
18+ only applies to delegated test results (ThreadsafeForwardingResult,
19+ MultiTestResult and ExtendedToOriginalDecorator) if the delegated to result
20+ is a testtools test result - we cannot reliably reset the state of unknown
21+ test result class instances. (Jonathan Lange, Robert Collins, #683332)
22
23 * Responsibility for running test cleanups has been moved to ``RunTest``.
24 This change does not affect public APIs and can be safely ignored by test
25
26=== modified file 'testtools/testresult/real.py'
27--- testtools/testresult/real.py 2010-11-30 12:54:20 +0000
28+++ testtools/testresult/real.py 2010-12-04 21:08:52 +0000
29@@ -35,13 +35,11 @@
30 """
31
32 def __init__(self):
33- super(TestResult, self).__init__()
34- self.skip_reasons = {}
35- self.__now = None
36- # -- Start: As per python 2.7 --
37- self.expectedFailures = []
38- self.unexpectedSuccesses = []
39- # -- End: As per python 2.7 --
40+ # startTestRun resets all attributes, and older clients don't know to
41+ # call startTestRun, so it is called once here.
42+ # Because subclasses may reasonably not expect this, we call the
43+ # specific version we want to run.
44+ TestResult.startTestRun(self)
45
46 def addExpectedFailure(self, test, err=None, details=None):
47 """Called when a test has failed in an expected manner.
48@@ -160,9 +158,13 @@
49
50 New in python 2.7
51 """
52+ super(TestResult, self).__init__()
53+ self.skip_reasons = {}
54+ self.__now = None
55+ # -- Start: As per python 2.7 --
56+ self.expectedFailures = []
57 self.unexpectedSuccesses = []
58- self.errors = []
59- self.failures = []
60+ # -- End: As per python 2.7 --
61
62 def stopTestRun(self):
63 """Called after a test run completes
64@@ -406,13 +408,11 @@
65
66 def __init__(self, decorated):
67 self.decorated = decorated
68- self._was_successful = True
69
70 def __getattr__(self, name):
71 return getattr(self.decorated, name)
72
73 def addError(self, test, err=None, details=None):
74- self._was_successful = False
75 self._check_args(err, details)
76 if details is not None:
77 try:
78@@ -437,7 +437,6 @@
79 return addExpectedFailure(test, err)
80
81 def addFailure(self, test, err=None, details=None):
82- self._was_successful = False
83 self._check_args(err, details)
84 if details is not None:
85 try:
86@@ -464,7 +463,6 @@
87 return addSkip(test, reason)
88
89 def addUnexpectedSuccess(self, test, details=None):
90- self._was_successful = False
91 outcome = getattr(self.decorated, 'addUnexpectedSuccess', None)
92 if outcome is None:
93 try:
94@@ -521,7 +519,6 @@
95 return self.decorated.startTest(test)
96
97 def startTestRun(self):
98- self._was_successful = True
99 try:
100 return self.decorated.startTestRun()
101 except AttributeError:
102@@ -552,7 +549,7 @@
103 return method(a_datetime)
104
105 def wasSuccessful(self):
106- return self._was_successful
107+ return self.decorated.wasSuccessful()
108
109
110 class _StringException(Exception):
111
112=== modified file 'testtools/tests/test_testresult.py'
113--- testtools/tests/test_testresult.py 2010-11-29 00:32:53 +0000
114+++ testtools/tests/test_testresult.py 2010-12-04 21:08:52 +0000
115@@ -132,7 +132,7 @@
116 result.stopTestRun()
117
118
119-class TestResultContract(Python27Contract):
120+class DetailsContract(Python27Contract):
121 """Tests for the contract of TestResults."""
122
123 def test_addExpectedFailure_details(self):
124@@ -171,6 +171,13 @@
125 result.startTest(self)
126 result.addSuccess(self, details={})
127
128+
129+class FallbackContract(DetailsContract):
130+ """When we fallback we take our policy choice to map calls.
131+
132+ For instance, we map unexpectedSuccess to an error code, not to success.
133+ """
134+
135 def test_addUnexpectedSuccess_was_successful(self):
136 # addUnexpectedSuccess fails test run in testtools.
137 result = self.makeResult()
138@@ -179,6 +186,14 @@
139 result.stopTest(self)
140 self.assertFalse(result.wasSuccessful())
141
142+
143+class StartTestRunContract(FallbackContract):
144+ """Defines the contract for testtools policy choices.
145+
146+ That is things which are not simply extensions to unittest but choices we
147+ have made differently.
148+ """
149+
150 def test_startTestRun_resets_unexpected_success(self):
151 result = self.makeResult()
152 result.startTest(self)
153@@ -203,25 +218,26 @@
154 result.startTestRun()
155 self.assertTrue(result.wasSuccessful())
156
157-class TestTestResultContract(TestCase, TestResultContract):
158+
159+class TestTestResultContract(TestCase, StartTestRunContract):
160
161 def makeResult(self):
162 return TestResult()
163
164
165-class TestMultiTestResultContract(TestCase, TestResultContract):
166+class TestMultiTestResultContract(TestCase, StartTestRunContract):
167
168 def makeResult(self):
169 return MultiTestResult(TestResult(), TestResult())
170
171
172-class TestTextTestResultContract(TestCase, TestResultContract):
173+class TestTextTestResultContract(TestCase, StartTestRunContract):
174
175 def makeResult(self):
176 return TextTestResult(StringIO())
177
178
179-class TestThreadSafeForwardingResultContract(TestCase, TestResultContract):
180+class TestThreadSafeForwardingResultContract(TestCase, StartTestRunContract):
181
182 def makeResult(self):
183 result_semaphore = threading.Semaphore(1)
184@@ -229,7 +245,7 @@
185 return ThreadsafeForwardingResult(target, result_semaphore)
186
187
188-class TestExtendedTestResultContract(TestCase, TestResultContract):
189+class TestExtendedTestResultContract(TestCase, StartTestRunContract):
190
191 def makeResult(self):
192 return ExtendedTestResult()
193@@ -241,7 +257,7 @@
194 return Python26TestResult()
195
196
197-class TestAdaptedPython26TestResultContract(TestCase, TestResultContract):
198+class TestAdaptedPython26TestResultContract(TestCase, FallbackContract):
199
200 def makeResult(self):
201 return ExtendedToOriginalDecorator(Python26TestResult())
202@@ -253,7 +269,7 @@
203 return Python27TestResult()
204
205
206-class TestAdaptedPython27TestResultContract(TestCase, TestResultContract):
207+class TestAdaptedPython27TestResultContract(TestCase, DetailsContract):
208
209 def makeResult(self):
210 return ExtendedToOriginalDecorator(Python27TestResult())

Subscribers

People subscribed via source and target branches