Merge lp:~jml/testtools/less-stack into lp:~testtools-committers/testtools/trunk

Proposed by Jonathan Lange
Status: Superseded
Proposed branch: lp:~jml/testtools/less-stack
Merge into: lp:~testtools-committers/testtools/trunk
Diff against target: 846 lines (+358/-58)
19 files modified
NEWS (+23/-1)
doc/for-framework-folk.rst (+8/-0)
doc/for-test-authors.rst (+25/-2)
testtools/__init__.py (+3/-0)
testtools/helpers.py (+13/-1)
testtools/matchers.py (+33/-4)
testtools/runtest.py (+5/-0)
testtools/testcase.py (+5/-0)
testtools/tests/__init__.py (+3/-2)
testtools/tests/helpers.py (+43/-7)
testtools/tests/test_deferredruntest.py (+2/-2)
testtools/tests/test_fixturesupport.py (+2/-2)
testtools/tests/test_helpers.py (+86/-0)
testtools/tests/test_matchers.py (+34/-6)
testtools/tests/test_runtest.py (+2/-2)
testtools/tests/test_testcase.py (+5/-3)
testtools/tests/test_testresult.py (+29/-16)
testtools/tests/test_testsuite.py (+21/-5)
testtools/testsuite.py (+16/-5)
To merge this branch: bzr merge lp:~jml/testtools/less-stack
Reviewer Review Type Date Requested Status
testtools developers Pending
Review via email: mp+68436@code.launchpad.net

Description of the change

Start of hiding irrelevant levels of stack.

Still need to re-enable them for testtools own development, and probably a way to make it easy to re-enable them for projects like fixtures and subunit that care a lot about testtools.

Have to say that the improvement is already obvious.

To post a comment you must log in.
lp:~jml/testtools/less-stack updated
206. By Jonathan Lange

Don't re-export from helpers.

207. By Jonathan Lange

Helper method to show and hide test results.

208. By Jonathan Lange

Cleanups

209. By Jonathan Lange

Add FixtureSuite and a fixture for hiding/showing the debug levels of stack.

210. By Jonathan Lange

Merge all-match helper in.

211. By Jonathan Lange

Merge AfterPreprocessing fix

212. By Jonathan Lange

Use matchers for better tests.

213. By Jonathan Lange

Make sure we show testtools own stack levels during run.

214. By Jonathan Lange

Be explicit in our higher level tests about what levels of the stack we
want to see.

Add a test that makes sure that the testtools stack levels are being shown
during a testtools run.

Fix the stack hiding control code to delete __unittest rather than set it
to False. This correctly hides stack levels.

215. By Jonathan Lange

Move safe_hasattr

216. By Jonathan Lange

Tests for safe_hasattr.

217. By Jonathan Lange

Document FixtureSuite

218. By Jonathan Lange

Docs and export.

219. By Jonathan Lange

More NEWS

220. By Jonathan Lange

Micro-optimize.

221. By Jonathan Lange

Switch to using a FunctionFixture, per Rob's suggestion.

222. By Jonathan Lange

Merge trunk

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'NEWS'
2--- NEWS 2011-07-20 08:48:46 +0000
3+++ NEWS 2011-07-20 12:59:27 +0000
4@@ -4,6 +4,15 @@
5 NEXT
6 ~~~~
7
8+Changes
9+-------
10+
11+* ``AfterPreproccessing`` renamed to ``AfterPreproccesing``, which is a more
12+ correct spelling. Old name preserved for backwards compatibility, but is
13+ now deprecated. Please stop using it.
14+ (Jonathan Lange, #813460)
15+
16+
17 Improvements
18 ------------
19
20@@ -16,6 +25,12 @@
21 * Correctly display non-ASCII unicode output on terminals that claim to have a
22 unicode encoding. (Martin [gz], #804122)
23
24+* ``FixtureSuite`` added, allows test suites to run with a given fixture.
25+ (Jonathan Lange)
26+
27+* Hide testtools's own stack frames when displaying tracebacks, making it
28+ easier for test authors to focus on their errors. (Jonathan Lange, #788974)
29+
30 * Less boilerplate displayed in test failures and errors.
31 (Jonathan Lange, #660852)
32
33@@ -27,7 +42,14 @@
34 * New convenience assertions, ``assertIsNone`` and ``assertIsNotNone``.
35 (Christian Kampka)
36
37-* New matcher, ``GreaterThan``. (Christian Kampka)
38+* New matchers:
39+
40+ * ``AllMatch`` matches many values against a single matcher.
41+ (Jonathan Lange, #615108)
42+
43+ * ``GreaterThan``. (Christian Kampka)
44+
45+* New helper, ``safe_hasattr`` added. (Jonathan Lange)
46
47
48 0.9.11
49
50=== modified file 'doc/for-framework-folk.rst'
51--- doc/for-framework-folk.rst 2010-12-22 20:36:40 +0000
52+++ doc/for-framework-folk.rst 2011-07-20 12:59:27 +0000
53@@ -182,5 +182,13 @@
54 objects with a run(result), runs them all in threads using the
55 ThreadsafeForwardingResult to coalesce their activity.
56
57+FixtureSuite
58+------------
59+
60+A test suite that sets up a fixture_ before running any tests, and then tears
61+it down after all of the tests are run. The fixture is *not* made available to
62+any of the tests.
63+
64 .. _`testtools API docs`: http://mumak.net/testtools/apidocs/
65 .. _unittest: http://docs.python.org/library/unittest.html
66+.. _fixture: http://pypi.python.org/pypi/fixtures
67
68=== modified file 'doc/for-test-authors.rst'
69--- doc/for-test-authors.rst 2011-07-19 15:37:07 +0000
70+++ doc/for-test-authors.rst 2011-07-20 12:59:27 +0000
71@@ -485,7 +485,7 @@
72 def HasFileContent(content):
73 def _read(path):
74 return open(path).read()
75- return AfterPreproccessing(_read, Equals(content))
76+ return AfterPreprocessing(_read, Equals(content))
77 self.assertThat('/tmp/foo.txt', PathHasFileContent("Hello world!"))
78
79
80@@ -539,6 +539,21 @@
81 self.assertThat(42, MatchesAny(Equals(5), Not(Equals(6))))
82
83
84+AllMatch
85+~~~~~~~~
86+
87+Matches many values against a single matcher. Can be used to make sure that
88+many things all meet the same condition::
89+
90+ def test_all_match_example(self):
91+ self.assertThat([2, 3, 5, 7], AllMatch(LessThan(10)))
92+
93+If the match fails, then all of the values that fail to match will be included
94+in the error message.
95+
96+In some ways, this is the converse of MatchesAll_.
97+
98+
99 MatchesListwise
100 ~~~~~~~~~~~~~~~
101
102@@ -741,7 +756,6 @@
103 arbitrary-color-name: {{{blue}}}
104
105 Traceback (most recent call last):
106- ...
107 File "exampletest.py", line 8, in test_thingy
108 1 / 0 # Gratuitous error!
109 ZeroDivisionError: integer division or modulo by zero
110@@ -1130,6 +1144,14 @@
111 StringIO = try_imports(['StringIO.StringIO', 'io.StringIO'])
112
113
114+Safe attribute testing
115+----------------------
116+
117+``hasattr`` is broken_ on many versions of Python. testtools provides
118+``safe_hasattr``, which can be used to safely test whether an object has a
119+particular attribute.
120+
121+
122 .. _testrepository: https://launchpad.net/testrepository
123 .. _Trial: http://twistedmatrix.com/documents/current/core/howto/testing.html
124 .. _nose: http://somethingaboutorange.com/mrl/projects/nose/
125@@ -1144,3 +1166,4 @@
126 .. _`testtools API docs`: http://mumak.net/testtools/apidocs/
127 .. _Distutils: http://docs.python.org/library/distutils.html
128 .. _`setup configuration`: http://docs.python.org/distutils/configfile.html
129+.. _broken: http://chipaca.com/post/3210673069/hasattr-17-less-harmful
130
131=== modified file 'testtools/__init__.py'
132--- testtools/__init__.py 2011-06-12 00:58:39 +0000
133+++ testtools/__init__.py 2011-07-20 12:59:27 +0000
134@@ -8,12 +8,14 @@
135 'ErrorHolder',
136 'ExpectedException',
137 'ExtendedToOriginalDecorator',
138+ 'FixtureSuite',
139 'iterate_tests',
140 'MultipleExceptions',
141 'MultiTestResult',
142 'PlaceHolder',
143 'run_test_with',
144 'TestCase',
145+ 'TestCommand',
146 'TestResult',
147 'TextTestResult',
148 'RunTest',
149@@ -59,6 +61,7 @@
150 )
151 from testtools.testsuite import (
152 ConcurrentTestSuite,
153+ FixtureSuite,
154 iterate_tests,
155 )
156 from testtools.distutilscmd import (
157
158=== modified file 'testtools/helpers.py'
159--- testtools/helpers.py 2011-06-30 15:51:58 +0000
160+++ testtools/helpers.py 2011-07-20 12:59:27 +0000
161@@ -1,6 +1,7 @@
162 # Copyright (c) 2010-2011 testtools developers. See LICENSE for details.
163
164 __all__ = [
165+ 'safe_hasattr',
166 'try_import',
167 'try_imports',
168 ]
169@@ -60,7 +61,7 @@
170 :param module_names: A sequence of module names to try to import.
171 :param alternative: The value to return if no module can be imported.
172 If unspecified, we raise an ImportError.
173- :param error_callback: If None, called with the ImportError for *each*
174+ :param error_callback: If None, called with the ImportError for *each*
175 module that fails to load.
176 :raises ImportError: If none of the modules can be imported and no
177 alternative value was specified.
178@@ -74,3 +75,14 @@
179 raise ImportError(
180 "Could not import any of: %s" % ', '.join(module_names))
181 return alternative
182+
183+
184+def safe_hasattr(obj, attr):
185+ """Does 'obj' have an attribute 'attr'?
186+
187+ Use this rather than built-in hasattr, as the built-in swallows exceptions
188+ in some versions of Python and behaves unpredictably with respect to
189+ properties.
190+ """
191+ marker = object()
192+ return getattr(obj, attr, marker) is not marker
193
194=== modified file 'testtools/matchers.py'
195--- testtools/matchers.py 2011-07-20 08:48:46 +0000
196+++ testtools/matchers.py 2011-07-20 12:59:27 +0000
197@@ -12,7 +12,8 @@
198
199 __metaclass__ = type
200 __all__ = [
201- 'AfterPreproccessing',
202+ 'AfterPreprocessing',
203+ 'AllMatch',
204 'Annotate',
205 'DocTestMatches',
206 'EndsWith',
207@@ -811,7 +812,7 @@
208 ).match(not_matched[:common_length])
209
210
211-class AfterPreproccessing(object):
212+class AfterPreprocessing(object):
213 """Matches if the value matches after passing through a function.
214
215 This can be used to aid in creating trivial matchers as functions, for
216@@ -820,7 +821,7 @@
217 def PathHasFileContent(content):
218 def _read(path):
219 return open(path).read()
220- return AfterPreproccessing(_read, Equals(content))
221+ return AfterPreprocessing(_read, Equals(content))
222 """
223
224 def __init__(self, preprocessor, matcher):
225@@ -833,7 +834,7 @@
226 return str(self.preprocessor)
227
228 def __str__(self):
229- return "AfterPreproccessing(%s, %s)" % (
230+ return "AfterPreprocessing(%s, %s)" % (
231 self._str_preprocessor(), self.matcher)
232
233 def match(self, value):
234@@ -841,3 +842,31 @@
235 return Annotate(
236 "after %s" % self._str_preprocessor(),
237 self.matcher).match(value)
238+
239+# This is the old, deprecated. spelling of the name, kept for backwards
240+# compatibility.
241+AfterPreproccessing = AfterPreprocessing
242+
243+
244+class AllMatch(object):
245+ """Matches if all provided values match the given matcher."""
246+
247+ def __init__(self, matcher):
248+ self.matcher = matcher
249+
250+ def __str__(self):
251+ return 'AllMatch(%s)' % (self.matcher,)
252+
253+ def match(self, values):
254+ mismatches = []
255+ for value in values:
256+ mismatch = self.matcher.match(value)
257+ if mismatch:
258+ mismatches.append(mismatch)
259+ if mismatches:
260+ return MismatchesAll(mismatches)
261+
262+
263+# Signal that this is part of the testing framework, and that code from this
264+# should not normally appear in tracebacks.
265+__unittest = True
266
267=== modified file 'testtools/runtest.py'
268--- testtools/runtest.py 2011-03-22 15:17:10 +0000
269+++ testtools/runtest.py 2011-07-20 12:59:27 +0000
270@@ -198,3 +198,8 @@
271 self._exceptions.append(e)
272 return self.exception_caught
273 raise e
274+
275+
276+# Signal that this is part of the testing framework, and that code from this
277+# should not normally appear in tracebacks.
278+__unittest = True
279
280=== modified file 'testtools/testcase.py'
281--- testtools/testcase.py 2011-06-20 11:57:32 +0000
282+++ testtools/testcase.py 2011-07-20 12:59:27 +0000
283@@ -772,3 +772,8 @@
284 raise AssertionError('"%s" does not match "%s".' %
285 (str(exc_value), self.value_re))
286 return True
287+
288+
289+# Signal that this is part of the testing framework, and that code from this
290+# should not normally appear in tracebacks.
291+__unittest = True
292
293=== modified file 'testtools/tests/__init__.py'
294--- testtools/tests/__init__.py 2011-07-11 10:30:08 +0000
295+++ testtools/tests/__init__.py 2011-07-20 12:59:27 +0000
296@@ -2,7 +2,8 @@
297
298 # See README for copyright and licensing details.
299
300-import unittest
301+from testtools.tests.helpers import StackHidingFixture
302+from testtools.testsuite import FixtureSuite
303
304
305 def test_suite():
306@@ -41,4 +42,4 @@
307 test_testsuite,
308 ]
309 suites = map(lambda x: x.test_suite(), modules)
310- return unittest.TestSuite(suites)
311+ return FixtureSuite(StackHidingFixture(False), suites)
312
313=== modified file 'testtools/tests/helpers.py'
314--- testtools/tests/helpers.py 2011-01-22 17:56:00 +0000
315+++ testtools/tests/helpers.py 2011-07-20 12:59:27 +0000
316@@ -1,15 +1,21 @@
317-# Copyright (c) 2008 testtools developers. See LICENSE for details.
318+# Copyright (c) 2008-2011 testtools developers. See LICENSE for details.
319
320 """Helpers for tests."""
321
322-import sys
323-
324-__metaclass__ = type
325 __all__ = [
326 'LoggingResult',
327 ]
328
329+import sys
330+
331+from fixtures import Fixture
332+
333 from testtools import TestResult
334+from testtools.helpers import (
335+ safe_hasattr,
336+ try_import,
337+ )
338+from testtools import runtest
339
340
341 # GZ 2010-08-12: Don't do this, pointlessly creates an exc_info cycle
342@@ -67,6 +73,36 @@
343 self._events.append(('time', a_datetime))
344 super(LoggingResult, self).time(a_datetime)
345
346-# Note, the following three classes are different to LoggingResult by
347-# being fully defined exact matches rather than supersets.
348-from testtools.testresult.doubles import *
349+
350+def is_stack_hidden():
351+ return safe_hasattr(runtest, '__unittest')
352+
353+
354+def hide_testtools_stack(should_hide=True):
355+ modules = [
356+ 'testtools.matchers',
357+ 'testtools.runtest',
358+ 'testtools.testcase',
359+ ]
360+ for module_name in modules:
361+ module = try_import(module_name)
362+ if should_hide:
363+ setattr(module, '__unittest', True)
364+ else:
365+ try:
366+ delattr(module, '__unittest')
367+ except AttributeError:
368+ # Attribute already doesn't exist. Our work here is done.
369+ pass
370+
371+
372+class StackHidingFixture(Fixture):
373+
374+ def __init__(self, should_hide):
375+ super(StackHidingFixture, self).__init__()
376+ self._should_hide = should_hide
377+
378+ def setUp(self):
379+ super(StackHidingFixture, self).setUp()
380+ self.addCleanup(hide_testtools_stack, is_stack_hidden())
381+ hide_testtools_stack(self._should_hide)
382
383=== modified file 'testtools/tests/test_deferredruntest.py'
384--- testtools/tests/test_deferredruntest.py 2011-01-22 17:56:00 +0000
385+++ testtools/tests/test_deferredruntest.py 2011-07-20 12:59:27 +0000
386@@ -1,4 +1,4 @@
387-# Copyright (c) 2010 testtools developers. See LICENSE for details.
388+# Copyright (c) 2010-2011 testtools developers. See LICENSE for details.
389
390 """Tests for the DeferredRunTest single test execution logic."""
391
392@@ -13,7 +13,6 @@
393 text_content,
394 )
395 from testtools.helpers import try_import
396-from testtools.tests.helpers import ExtendedTestResult
397 from testtools.matchers import (
398 Equals,
399 KeysEqual,
400@@ -21,6 +20,7 @@
401 Raises,
402 )
403 from testtools.runtest import RunTest
404+from testtools.testresult.doubles import ExtendedTestResult
405 from testtools.tests.test_spinner import NeedsTwistedTestCase
406
407 assert_fails_with = try_import('testtools.deferredruntest.assert_fails_with')
408
409=== modified file 'testtools/tests/test_fixturesupport.py'
410--- testtools/tests/test_fixturesupport.py 2011-05-25 15:03:35 +0000
411+++ testtools/tests/test_fixturesupport.py 2011-07-20 12:59:27 +0000
412@@ -1,4 +1,4 @@
413-# Copyright (c) 2010 testtools developers. See LICENSE for details.
414+# Copyright (c) 2010-2011 testtools developers. See LICENSE for details.
415
416 import unittest
417
418@@ -8,7 +8,7 @@
419 content_type,
420 )
421 from testtools.helpers import try_import
422-from testtools.tests.helpers import (
423+from testtools.testresult.doubles import (
424 ExtendedTestResult,
425 )
426
427
428=== modified file 'testtools/tests/test_helpers.py'
429--- testtools/tests/test_helpers.py 2011-06-30 15:51:58 +0000
430+++ testtools/tests/test_helpers.py 2011-07-20 12:59:27 +0000
431@@ -6,10 +6,18 @@
432 try_imports,
433 )
434 from testtools.matchers import (
435+ AllMatch,
436+ AfterPreprocessing,
437 Equals,
438 Is,
439 Not,
440 )
441+from testtools.tests.helpers import (
442+ hide_testtools_stack,
443+ is_stack_hidden,
444+ safe_hasattr,
445+ StackHidingFixture,
446+ )
447
448
449 def check_error_callback(test, function, arg, expected_error_count,
450@@ -39,6 +47,37 @@
451 test.assertEquals(len(cb_calls), expected_error_count)
452
453
454+class TestSafeHasattr(TestCase):
455+
456+ def test_attribute_not_there(self):
457+ class Foo(object):
458+ pass
459+ self.assertEqual(False, safe_hasattr(Foo(), 'anything'))
460+
461+ def test_attribute_there(self):
462+ class Foo(object):
463+ pass
464+ foo = Foo()
465+ foo.attribute = None
466+ self.assertEqual(True, safe_hasattr(foo, 'attribute'))
467+
468+ def test_property_there(self):
469+ class Foo(object):
470+ @property
471+ def attribute(self):
472+ return None
473+ foo = Foo()
474+ self.assertEqual(True, safe_hasattr(foo, 'attribute'))
475+
476+ def test_property_raises(self):
477+ class Foo(object):
478+ @property
479+ def attribute(self):
480+ 1/0
481+ foo = Foo()
482+ self.assertRaises(ZeroDivisionError, safe_hasattr, foo, 'attribute')
483+
484+
485 class TestTryImport(TestCase):
486
487 def test_doesnt_exist(self):
488@@ -154,6 +193,53 @@
489 0, True)
490
491
492+import testtools.matchers
493+import testtools.runtest
494+import testtools.testcase
495+
496+
497+def StackHidden(is_hidden):
498+ return AllMatch(
499+ AfterPreprocessing(
500+ lambda module: safe_hasattr(module, '__unittest'),
501+ Equals(is_hidden)))
502+
503+
504+class TestStackHiding(TestCase):
505+
506+ modules = [
507+ testtools.matchers,
508+ testtools.runtest,
509+ testtools.testcase,
510+ ]
511+
512+ def setUp(self):
513+ super(TestStackHiding, self).setUp()
514+ self.addCleanup(hide_testtools_stack, is_stack_hidden())
515+
516+ def test_shown_during_testtools_testsuite(self):
517+ self.assertThat(self.modules, StackHidden(False))
518+
519+ def test_is_stack_hidden_consistent_true(self):
520+ hide_testtools_stack(True)
521+ self.assertEqual(True, is_stack_hidden())
522+
523+ def test_is_stack_hidden_consistent_false(self):
524+ hide_testtools_stack(False)
525+ self.assertEqual(False, is_stack_hidden())
526+
527+ def test_show_stack(self):
528+ hide_testtools_stack(False)
529+ self.assertThat(self.modules, StackHidden(False))
530+
531+ def test_fixture(self):
532+ current_state = is_stack_hidden()
533+ fixture = StackHidingFixture(not current_state)
534+ with fixture:
535+ self.assertThat(self.modules, StackHidden(not current_state))
536+ self.assertThat(self.modules, StackHidden(current_state))
537+
538+
539 def test_suite():
540 from unittest import TestLoader
541 return TestLoader().loadTestsFromName(__name__)
542
543=== modified file 'testtools/tests/test_matchers.py'
544--- testtools/tests/test_matchers.py 2011-07-20 08:46:46 +0000
545+++ testtools/tests/test_matchers.py 2011-07-20 12:59:27 +0000
546@@ -14,7 +14,8 @@
547 StringIO,
548 )
549 from testtools.matchers import (
550- AfterPreproccessing,
551+ AfterPreprocessing,
552+ AllMatch,
553 Annotate,
554 AnnotatedMismatch,
555 Equals,
556@@ -698,24 +699,24 @@
557 re.S))
558
559
560-class TestAfterPreproccessing(TestCase, TestMatchersInterface):
561+class TestAfterPreprocessing(TestCase, TestMatchersInterface):
562
563 def parity(x):
564 return x % 2
565
566- matches_matcher = AfterPreproccessing(parity, Equals(1))
567+ matches_matcher = AfterPreprocessing(parity, Equals(1))
568 matches_matches = [3, 5]
569 matches_mismatches = [2]
570
571 str_examples = [
572- ("AfterPreproccessing(<function parity>, Equals(1))",
573- AfterPreproccessing(parity, Equals(1))),
574+ ("AfterPreprocessing(<function parity>, Equals(1))",
575+ AfterPreprocessing(parity, Equals(1))),
576 ]
577
578 describe_examples = [
579 ("1 != 0: after <function parity>",
580 2,
581- AfterPreproccessing(parity, Equals(1))),
582+ AfterPreprocessing(parity, Equals(1))),
583 ]
584
585
586@@ -739,6 +740,33 @@
587 repr(decorated))
588
589
590+class TestAllMatch(TestCase, TestMatchersInterface):
591+
592+ matches_matcher = AllMatch(LessThan(10))
593+ matches_matches = [
594+ [9, 9, 9],
595+ (9, 9),
596+ iter([9, 9, 9, 9, 9]),
597+ ]
598+ matches_mismatches = [
599+ [11, 9, 9],
600+ iter([9, 12, 9, 11]),
601+ ]
602+
603+ str_examples = [
604+ ("AllMatch(LessThan(12))", AllMatch(LessThan(12))),
605+ ]
606+
607+ describe_examples = [
608+ ('Differences: [\n'
609+ '10 is not > 11\n'
610+ '10 is not > 10\n'
611+ ']',
612+ [11, 9, 10],
613+ AllMatch(LessThan(10))),
614+ ]
615+
616+
617 def test_suite():
618 from unittest import TestLoader
619 return TestLoader().loadTestsFromName(__name__)
620
621=== modified file 'testtools/tests/test_runtest.py'
622--- testtools/tests/test_runtest.py 2011-01-22 17:56:00 +0000
623+++ testtools/tests/test_runtest.py 2011-07-20 12:59:27 +0000
624@@ -1,4 +1,4 @@
625-# Copyright (c) 2009-2010 testtools developers. See LICENSE for details.
626+# Copyright (c) 2009-2011 testtools developers. See LICENSE for details.
627
628 """Tests for the RunTest single test execution logic."""
629
630@@ -10,7 +10,7 @@
631 TestResult,
632 )
633 from testtools.matchers import MatchesException, Is, Raises
634-from testtools.tests.helpers import ExtendedTestResult
635+from testtools.testresult.doubles import ExtendedTestResult
636
637
638 class TestRunTest(TestCase):
639
640=== modified file 'testtools/tests/test_testcase.py'
641--- testtools/tests/test_testcase.py 2011-07-11 10:30:08 +0000
642+++ testtools/tests/test_testcase.py 2011-07-20 12:59:27 +0000
643@@ -23,12 +23,14 @@
644 MatchesException,
645 Raises,
646 )
647+from testtools.testresult.doubles import (
648+ Python26TestResult,
649+ Python27TestResult,
650+ ExtendedTestResult,
651+ )
652 from testtools.tests.helpers import (
653 an_exc_info,
654 LoggingResult,
655- Python26TestResult,
656- Python27TestResult,
657- ExtendedTestResult,
658 )
659 try:
660 exec('from __future__ import with_statement')
661
662=== modified file 'testtools/tests/test_testresult.py'
663--- testtools/tests/test_testresult.py 2011-07-01 10:50:54 +0000
664+++ testtools/tests/test_testresult.py 2011-07-20 12:59:27 +0000
665@@ -44,11 +44,14 @@
666 Raises,
667 )
668 from testtools.tests.helpers import (
669+ an_exc_info,
670 LoggingResult,
671+ StackHidingFixture,
672+ )
673+from testtools.testresult.doubles import (
674 Python26TestResult,
675 Python27TestResult,
676 ExtendedTestResult,
677- an_exc_info
678 )
679 from testtools.testresult.real import (
680 _details_to_str,
681@@ -369,7 +372,10 @@
682 result.time(now)
683 self.assertEqual(now, result._now())
684
685- def test_traceback_formatting(self):
686+ def test_traceback_formatting_without_stack_hidden(self):
687+ # During the testtools test run, we show our levels of the stack,
688+ # because we want to be able to use our test suite to debug our own
689+ # code.
690 result = self.makeResult()
691 test = make_erroring_test()
692 test.run(result)
693@@ -386,6 +392,20 @@
694 'ZeroDivisionError: ...\n',
695 doctest.ELLIPSIS))
696
697+ def test_traceback_formatting_with_stack_hidden(self):
698+ result = self.makeResult()
699+ test = make_erroring_test()
700+ with StackHidingFixture(True):
701+ test.run(result)
702+ self.assertThat(
703+ result.errors[0][1],
704+ DocTestMatches(
705+ 'Traceback (most recent call last):\n'
706+ ' File "testtools/tests/test_testresult.py", line ..., in error\n'
707+ ' 1/0\n'
708+ 'ZeroDivisionError: ...\n',
709+ doctest.ELLIPSIS))
710+
711
712 class TestMultiTestResult(TestCase):
713 """Tests for 'MultiTestResult'."""
714@@ -575,21 +595,18 @@
715 DocTestMatches("...\nFAILED (failures=1)\n", doctest.ELLIPSIS))
716
717 def test_stopTestRun_shows_details(self):
718- self.result.startTestRun()
719- make_erroring_test().run(self.result)
720- make_unexpectedly_successful_test().run(self.result)
721- make_failing_test().run(self.result)
722- self.reset_output()
723- self.result.stopTestRun()
724+ with StackHidingFixture(True):
725+ self.result.startTestRun()
726+ make_erroring_test().run(self.result)
727+ make_unexpectedly_successful_test().run(self.result)
728+ make_failing_test().run(self.result)
729+ self.reset_output()
730+ self.result.stopTestRun()
731 self.assertThat(self.getvalue(),
732 DocTestMatches("""...======================================================================
733 ERROR: testtools.tests.test_testresult.Test.error
734 ----------------------------------------------------------------------
735 Traceback (most recent call last):
736- File "...testtools...runtest.py", line ..., in _run_user...
737- return fn(*args, **kwargs)
738- File "...testtools...testcase.py", line ..., in _run_test_method
739- return self._get_test_method()()
740 File "...testtools...tests...test_testresult.py", line ..., in error
741 1/0
742 ZeroDivisionError:... divi... by zero...
743@@ -597,10 +614,6 @@
744 FAIL: testtools.tests.test_testresult.Test.failed
745 ----------------------------------------------------------------------
746 Traceback (most recent call last):
747- File "...testtools...runtest.py", line ..., in _run_user...
748- return fn(*args, **kwargs)
749- File "...testtools...testcase.py", line ..., in _run_test_method
750- return self._get_test_method()()
751 File "...testtools...tests...test_testresult.py", line ..., in failed
752 self.fail("yo!")
753 AssertionError: yo!
754
755=== modified file 'testtools/tests/test_testsuite.py'
756--- testtools/tests/test_testsuite.py 2011-01-22 17:56:00 +0000
757+++ testtools/tests/test_testsuite.py 2011-07-20 12:59:27 +0000
758@@ -1,20 +1,19 @@
759-# Copyright (c) 2009 testtools developers. See LICENSE for details.
760+# Copyright (c) 2009-2011 testtools developers. See LICENSE for details.
761
762 """Test ConcurrentTestSuite and related things."""
763
764 __metaclass__ = type
765
766-import datetime
767 import unittest
768
769+from fixtures import FunctionFixture
770+
771 from testtools import (
772 ConcurrentTestSuite,
773 iterate_tests,
774 TestCase,
775 )
776-from testtools.matchers import (
777- Equals,
778- )
779+from testtools.testsuite import FixtureSuite
780 from testtools.tests.helpers import LoggingResult
781
782
783@@ -48,6 +47,23 @@
784 return tests[0], tests[1]
785
786
787+class TestFixtureSuite(TestCase):
788+
789+ def test_fixture_suite(self):
790+ log = []
791+ class Sample(TestCase):
792+ def test_one(self):
793+ log.append(1)
794+ def test_two(self):
795+ log.append(2)
796+ fixture = FunctionFixture(
797+ lambda: log.append('setUp'),
798+ lambda fixture: log.append('tearDown'))
799+ suite = FixtureSuite(fixture, [Sample('test_one'), Sample('test_two')])
800+ suite.run(LoggingResult([]))
801+ self.assertEqual(['setUp', 1, 2, 'tearDown'], log)
802+
803+
804 def test_suite():
805 from unittest import TestLoader
806 return TestLoader().loadTestsFromName(__name__)
807
808=== modified file 'testtools/testsuite.py'
809--- testtools/testsuite.py 2011-01-22 17:56:00 +0000
810+++ testtools/testsuite.py 2011-07-20 12:59:27 +0000
811@@ -1,4 +1,4 @@
812-# Copyright (c) 2009 testtools developers. See LICENSE for details.
813+# Copyright (c) 2009-2011 testtools developers. See LICENSE for details.
814
815 """Test suites and related things."""
816
817@@ -8,10 +8,10 @@
818 'iterate_tests',
819 ]
820
821-try:
822- from Queue import Queue
823-except ImportError:
824- from queue import Queue
825+from testtools.helpers import try_imports
826+
827+Queue = try_imports(['Queue.Queue', 'queue.Queue'])
828+
829 import threading
830 import unittest
831
832@@ -85,3 +85,14 @@
833 test.run(process_result)
834 finally:
835 queue.put(test)
836+
837+
838+class FixtureSuite(unittest.TestSuite):
839+
840+ def __init__(self, fixture, tests):
841+ super(FixtureSuite, self).__init__(tests)
842+ self._fixture = fixture
843+
844+ def run(self, result):
845+ with self._fixture:
846+ super(FixtureSuite, self).run(result)

Subscribers

People subscribed via source and target branches