Merge lp:~lifeless/testtools/fixtures into lp:~testtools-committers/testtools/trunk

Proposed by Robert Collins
Status: Merged
Approved by: Jonathan Lange
Approved revision: 122
Merged at revision: 124
Proposed branch: lp:~lifeless/testtools/fixtures
Merge into: lp:~testtools-committers/testtools/trunk
Diff against target: 184 lines (+108/-2)
5 files modified
MANUAL (+10/-0)
NEWS (+3/-0)
README (+9/-2)
testtools/testcase.py (+29/-0)
testtools/tests/test_testtools.py (+57/-0)
To merge this branch: bzr merge lp:~lifeless/testtools/fixtures
Reviewer Review Type Date Requested Status
Jonathan Lange Approve
Review via email: mp+39388@code.launchpad.net

Description of the change

useFixture. Woo.

To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MANUAL'
2--- MANUAL 2010-10-17 16:34:55 +0000
3+++ MANUAL 2010-10-26 16:56:50 +0000
4@@ -116,6 +116,16 @@
5 ``skipTest`` support, the ``skip`` name is now deprecated (but no warning
6 is emitted yet - some time in the future we may do so).
7
8+TestCase.useFixture
9+~~~~~~~~~~~~~~~~~~~
10+
11+``useFixture(fixture)`` calls setUp on the fixture, schedules a cleanup to
12+clean it up, and schedules a cleanup to attach all details held by the
13+fixture to the details dict of the test case. The fixture object should meet
14+the ``fixtures.Fixture`` protocol (version 0.3.4 or newer). This is useful
15+for moving code out of setUp and tearDown methods and into composable side
16+classes.
17+
18
19 New assertion methods
20 ~~~~~~~~~~~~~~~~~~~~~
21
22=== modified file 'NEWS'
23--- NEWS 2010-10-25 22:10:37 +0000
24+++ NEWS 2010-10-26 16:56:50 +0000
25@@ -24,6 +24,9 @@
26 * addUnexpectedSuccess is translated to addFailure for test results that don't
27 know about addUnexpectedSuccess. (Jonathan Lange, #654474)
28
29+* ``testools.TestCase.useFixture`` has been added to glue with fixtures nicely.
30+ (Robert Collins)
31+
32
33 0.9.7
34 ~~~~~
35
36=== modified file 'README'
37--- README 2010-10-24 08:46:03 +0000
38+++ README 2010-10-26 16:56:50 +0000
39@@ -19,14 +19,21 @@
40 distributed under the same license as Python, see LICENSE for details.
41
42
43-Dependencies
44-------------
45+Required Dependencies
46+---------------------
47
48 * Python 2.4+ or 3.0+
49
50+Optional Dependencies
51+---------------------
52+
53 If you would like to use our undocumented, unsupported Twisted support, then
54 you will need Twisted.
55
56+If you want to use ``fixtures`` then you can either install fixtures (e.g. from
57+https://launchpad.net/python-fixtures or http://pypi.python.org/pypi/fixtures)
58+or alternatively just make sure your fixture objects obey the same protocol.
59+
60
61 Bug reports and patches
62 -----------------------
63
64=== modified file 'testtools/testcase.py'
65--- testtools/testcase.py 2010-10-18 12:46:20 +0000
66+++ testtools/testcase.py 2010-10-26 16:56:50 +0000
67@@ -538,6 +538,35 @@
68 """
69 return self._get_test_method()()
70
71+ def useFixture(self, fixture):
72+ """Use fixture in a test case.
73+
74+ The fixture will be setUp, and self.addCleanup(fixture.cleanUp) called.
75+
76+ :param fixture: The fixture to use.
77+ :return: The fixture, after setting it up and scheduling a cleanup for
78+ it.
79+ """
80+ fixture.setUp()
81+ self.addCleanup(fixture.cleanUp)
82+ self.addCleanup(self._gather_details, fixture.getDetails)
83+ return fixture
84+
85+ def _gather_details(self, getDetails):
86+ """Merge the details from getDetails() into self.getDetails()."""
87+ details = getDetails()
88+ my_details = self.getDetails()
89+ for name, content_object in details.items():
90+ new_name = name
91+ disambiguator = itertools.count(1)
92+ while new_name in my_details:
93+ new_name = '%s-%d' % (name, advance_iterator(disambiguator))
94+ name = new_name
95+ content_bytes = list(content_object.iter_bytes())
96+ content_callback = lambda:content_bytes
97+ self.addDetail(name,
98+ content.Content(content_object.content_type, content_callback))
99+
100 def setUp(self):
101 unittest.TestCase.setUp(self)
102 self.__setup_called = True
103
104=== modified file 'testtools/tests/test_testtools.py'
105--- testtools/tests/test_testtools.py 2010-09-26 20:45:28 +0000
106+++ testtools/tests/test_testtools.py 2010-10-26 16:56:50 +0000
107@@ -6,6 +6,9 @@
108 import sys
109 import unittest
110
111+import fixtures
112+from fixtures.tests.helpers import LoggingFixture
113+
114 from testtools import (
115 ErrorHolder,
116 MultipleExceptions,
117@@ -13,6 +16,7 @@
118 TestCase,
119 clone_test_with_new_id,
120 content,
121+ content_type,
122 skip,
123 skipIf,
124 skipUnless,
125@@ -1122,6 +1126,59 @@
126 self.assertIs(marker, value)
127
128
129+class TestFixtureSupport(TestCase):
130+
131+ def test_useFixture(self):
132+ fixture = LoggingFixture()
133+ class SimpleTest(TestCase):
134+ def test_foo(self):
135+ self.useFixture(fixture)
136+ result = unittest.TestResult()
137+ SimpleTest('test_foo').run(result)
138+ self.assertTrue(result.wasSuccessful())
139+ self.assertEqual(['setUp', 'cleanUp'], fixture.calls)
140+
141+ def test_useFixture_cleanups_raise_caught(self):
142+ calls = []
143+ def raiser(ignored):
144+ calls.append('called')
145+ raise Exception('foo')
146+ fixture = fixtures.FunctionFixture(lambda:None, raiser)
147+ class SimpleTest(TestCase):
148+ def test_foo(self):
149+ self.useFixture(fixture)
150+ result = unittest.TestResult()
151+ SimpleTest('test_foo').run(result)
152+ self.assertFalse(result.wasSuccessful())
153+ self.assertEqual(['called'], calls)
154+
155+ def test_useFixture_details_captured(self):
156+ class DetailsFixture(fixtures.Fixture):
157+ def setUp(self):
158+ fixtures.Fixture.setUp(self)
159+ self.addCleanup(delattr, self, 'content')
160+ self.content = ['content available until cleanUp']
161+ self.addDetail('content',
162+ content.Content(content_type.UTF8_TEXT, self.get_content))
163+ def get_content(self):
164+ return self.content
165+ fixture = DetailsFixture()
166+ class SimpleTest(TestCase):
167+ def test_foo(self):
168+ self.useFixture(fixture)
169+ # Add a colliding detail (both should show up)
170+ self.addDetail('content',
171+ content.Content(content_type.UTF8_TEXT, lambda:['foo']))
172+ result = ExtendedTestResult()
173+ SimpleTest('test_foo').run(result)
174+ self.assertEqual('addSuccess', result._events[-2][0])
175+ details = result._events[-2][2]
176+ self.assertEqual(['content', 'content-1'], sorted(details.keys()))
177+ self.assertEqual('foo', ''.join(details['content'].iter_text()))
178+ self.assertEqual('content available until cleanUp',
179+ ''.join(details['content-1'].iter_text()))
180+
181+
182 def test_suite():
183 from unittest import TestLoader
184 return TestLoader().loadTestsFromName(__name__)

Subscribers

People subscribed via source and target branches