Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> |
2 | <html> | |
3 | <head> | |
4 | <link rel="STYLESHEET" href="lib.css" type='text/css' /> | |
5 | <link rel="SHORTCUT ICON" href="../icons/pyfav.png" type="image/png" /> | |
6 | <link rel='start' href='../index.html' title='Python Documentation Index' /> | |
7 | <link rel="first" href="lib.html" title='Python Library Reference' /> | |
8 | <link rel='contents' href='contents.html' title="Contents" /> | |
9 | <link rel='index' href='genindex.html' title='Index' /> | |
10 | <link rel='last' href='about.html' title='About this document...' /> | |
11 | <link rel='help' href='about.html' title='About this document...' /> | |
12 | <link rel="next" href="legacy-unit-tests.html" /> | |
13 | <link rel="prev" href="node164.html" /> | |
14 | <link rel="parent" href="module-unittest.html" /> | |
15 | <link rel="next" href="legacy-unit-tests.html" /> | |
16 | <meta name='aesop' content='information' /> | |
17 | <title>5.3.2 Organizing test code </title> | |
18 | </head> | |
19 | <body> | |
20 | <DIV CLASS="navigation"> | |
21 | <div id='top-navigation-panel' xml:id='top-navigation-panel'> | |
22 | <table align="center" width="100%" cellpadding="0" cellspacing="2"> | |
23 | <tr> | |
24 | <td class='online-navigation'><a rel="prev" title="5.3.1 Basic example" | |
25 | href="node164.html"><img src='../icons/previous.png' | |
26 | border='0' height='32' alt='Previous Page' width='32' /></A></td> | |
27 | <td class='online-navigation'><a rel="parent" title="5.3 unittest " | |
28 | href="module-unittest.html"><img src='../icons/up.png' | |
29 | border='0' height='32' alt='Up One Level' width='32' /></A></td> | |
30 | <td class='online-navigation'><a rel="next" title="5.3.3 Re-using old test" | |
31 | href="legacy-unit-tests.html"><img src='../icons/next.png' | |
32 | border='0' height='32' alt='Next Page' width='32' /></A></td> | |
33 | <td align="center" width="100%">Python Library Reference</td> | |
34 | <td class='online-navigation'><a rel="contents" title="Table of Contents" | |
35 | href="contents.html"><img src='../icons/contents.png' | |
36 | border='0' height='32' alt='Contents' width='32' /></A></td> | |
37 | <td class='online-navigation'><a href="modindex.html" title="Module Index"><img src='../icons/modules.png' | |
38 | border='0' height='32' alt='Module Index' width='32' /></a></td> | |
39 | <td class='online-navigation'><a rel="index" title="Index" | |
40 | href="genindex.html"><img src='../icons/index.png' | |
41 | border='0' height='32' alt='Index' width='32' /></A></td> | |
42 | </tr></table> | |
43 | <div class='online-navigation'> | |
44 | <b class="navlabel">Previous:</b> | |
45 | <a class="sectref" rel="prev" href="node164.html">5.3.1 Basic example</A> | |
46 | <b class="navlabel">Up:</b> | |
47 | <a class="sectref" rel="parent" href="module-unittest.html">5.3 unittest </A> | |
48 | <b class="navlabel">Next:</b> | |
49 | <a class="sectref" rel="next" href="legacy-unit-tests.html">5.3.3 Re-using old test</A> | |
50 | </div> | |
51 | <hr /></div> | |
52 | </DIV> | |
53 | <!--End of Navigation Panel--> | |
54 | ||
55 | <H2><A NAME="SECTION007320000000000000000"></A><A NAME="organizing-tests"></A> | |
56 | <BR> | |
57 | 5.3.2 Organizing test code | |
58 | ||
59 | </H2> | |
60 | ||
61 | <P> | |
62 | The basic building blocks of unit testing are <i class="dfn">test cases</i> -- | |
63 | single scenarios that must be set up and checked for correctness. In | |
64 | PyUnit, test cases are represented by instances of the | |
65 | <tt class="class">TestCase</tt> class in the <tt class="module"><a href="module-unittest.html">unittest</a></tt> module. To make | |
66 | your own test cases you must write subclasses of <tt class="class">TestCase</tt>, or | |
67 | use <tt class="class">FunctionTestCase</tt>. | |
68 | ||
69 | <P> | |
70 | An instance of a <tt class="class">TestCase</tt>-derived class is an object that can | |
71 | completely run a single test method, together with optional set-up | |
72 | and tidy-up code. | |
73 | ||
74 | <P> | |
75 | The testing code of a <tt class="class">TestCase</tt> instance should be entirely | |
76 | self contained, such that it can be run either in isolation or in | |
77 | arbitrary combination with any number of other test cases. | |
78 | ||
79 | <P> | |
80 | The simplest test case subclass will simply override the | |
81 | <tt class="method">runTest()</tt> method in order to perform specific testing code: | |
82 | ||
83 | <P> | |
84 | <div class="verbatim"><pre> | |
85 | import unittest | |
86 | ||
87 | class DefaultWidgetSizeTestCase(unittest.TestCase): | |
88 | def runTest(self): | |
89 | widget = Widget("The widget") | |
90 | self.failUnless(widget.size() == (50,50), 'incorrect default size') | |
91 | </pre></div> | |
92 | ||
93 | <P> | |
94 | Note that in order to test something, we use the one of the | |
95 | <tt class="method">assert*()</tt> or <tt class="method">fail*()</tt> methods provided by the | |
96 | <tt class="class">TestCase</tt> base class. If the test fails when the test case | |
97 | runs, an exception will be raised, and the testing framework will | |
98 | identify the test case as a <i class="dfn">failure</i>. Other exceptions that do | |
99 | not arise from checks made through the <tt class="method">assert*()</tt> and | |
100 | <tt class="method">fail*()</tt> methods are identified by the testing framework as | |
101 | dfnerrors. | |
102 | ||
103 | <P> | |
104 | The way to run a test case will be described later. For now, note | |
105 | that to construct an instance of such a test case, we call its | |
106 | constructor without arguments: | |
107 | ||
108 | <P> | |
109 | <div class="verbatim"><pre> | |
110 | testCase = DefaultWidgetSizeTestCase() | |
111 | </pre></div> | |
112 | ||
113 | <P> | |
114 | Now, such test cases can be numerous, and their set-up can be | |
115 | repetitive. In the above case, constructing a ``Widget'' in each of | |
116 | 100 Widget test case subclasses would mean unsightly duplication. | |
117 | ||
118 | <P> | |
119 | Luckily, we can factor out such set-up code by implementing a method | |
120 | called <tt class="method">setUp()</tt>, which the testing framework will | |
121 | automatically call for us when we run the test: | |
122 | ||
123 | <P> | |
124 | <div class="verbatim"><pre> | |
125 | import unittest | |
126 | ||
127 | class SimpleWidgetTestCase(unittest.TestCase): | |
128 | def setUp(self): | |
129 | self.widget = Widget("The widget") | |
130 | ||
131 | class DefaultWidgetSizeTestCase(SimpleWidgetTestCase): | |
132 | def runTest(self): | |
133 | self.failUnless(self.widget.size() == (50,50), | |
134 | 'incorrect default size') | |
135 | ||
136 | class WidgetResizeTestCase(SimpleWidgetTestCase): | |
137 | def runTest(self): | |
138 | self.widget.resize(100,150) | |
139 | self.failUnless(self.widget.size() == (100,150), | |
140 | 'wrong size after resize') | |
141 | </pre></div> | |
142 | ||
143 | <P> | |
144 | If the <tt class="method">setUp()</tt> method raises an exception while the test is | |
145 | running, the framework will consider the test to have suffered an | |
146 | error, and the <tt class="method">runTest()</tt> method will not be executed. | |
147 | ||
148 | <P> | |
149 | Similarly, we can provide a <tt class="method">tearDown()</tt> method that tidies up | |
150 | after the <tt class="method">runTest()</tt> method has been run: | |
151 | ||
152 | <P> | |
153 | <div class="verbatim"><pre> | |
154 | import unittest | |
155 | ||
156 | class SimpleWidgetTestCase(unittest.TestCase): | |
157 | def setUp(self): | |
158 | self.widget = Widget("The widget") | |
159 | ||
160 | def tearDown(self): | |
161 | self.widget.dispose() | |
162 | self.widget = None | |
163 | </pre></div> | |
164 | ||
165 | <P> | |
166 | If <tt class="method">setUp()</tt> succeeded, the <tt class="method">tearDown()</tt> method will be | |
167 | run regardless of whether or not <tt class="method">runTest()</tt> succeeded. | |
168 | ||
169 | <P> | |
170 | Such a working environment for the testing code is called a | |
171 | <i class="dfn">fixture</i>. | |
172 | ||
173 | <P> | |
174 | Often, many small test cases will use the same fixture. In this case, | |
175 | we would end up subclassing <tt class="class">SimpleWidgetTestCase</tt> into many | |
176 | small one-method classes such as | |
177 | <tt class="class">DefaultWidgetSizeTestCase</tt>. This is time-consuming and | |
178 | discouraging, so in the same vein as JUnit, PyUnit provides a simpler | |
179 | mechanism: | |
180 | ||
181 | <P> | |
182 | <div class="verbatim"><pre> | |
183 | import unittest | |
184 | ||
185 | class WidgetTestCase(unittest.TestCase): | |
186 | def setUp(self): | |
187 | self.widget = Widget("The widget") | |
188 | ||
189 | def tearDown(self): | |
190 | self.widget.dispose() | |
191 | self.widget = None | |
192 | ||
193 | def testDefaultSize(self): | |
194 | self.failUnless(self.widget.size() == (50,50), | |
195 | 'incorrect default size') | |
196 | ||
197 | def testResize(self): | |
198 | self.widget.resize(100,150) | |
199 | self.failUnless(self.widget.size() == (100,150), | |
200 | 'wrong size after resize') | |
201 | </pre></div> | |
202 | ||
203 | <P> | |
204 | Here we have not provided a <tt class="method">runTest()</tt> method, but have | |
205 | instead provided two different test methods. Class instances will now | |
206 | each run one of the <tt class="method">test*()</tt> methods, with <code>self.widget</code> | |
207 | created and destroyed separately for each instance. When creating an | |
208 | instance we must specify the test method it is to run. We do this by | |
209 | passing the method name in the constructor: | |
210 | ||
211 | <P> | |
212 | <div class="verbatim"><pre> | |
213 | defaultSizeTestCase = WidgetTestCase("testDefaultSize") | |
214 | resizeTestCase = WidgetTestCase("testResize") | |
215 | </pre></div> | |
216 | ||
217 | <P> | |
218 | Test case instances are grouped together according to the features | |
219 | they test. PyUnit provides a mechanism for this: the <tt class="class">test | |
220 | suite</tt>, represented by the class <tt class="class">TestSuite</tt> in the | |
221 | <tt class="module"><a href="module-unittest.html">unittest</a></tt> module: | |
222 | ||
223 | <P> | |
224 | <div class="verbatim"><pre> | |
225 | widgetTestSuite = unittest.TestSuite() | |
226 | widgetTestSuite.addTest(WidgetTestCase("testDefaultSize")) | |
227 | widgetTestSuite.addTest(WidgetTestCase("testResize")) | |
228 | </pre></div> | |
229 | ||
230 | <P> | |
231 | For the ease of running tests, as we will see later, it is a good | |
232 | idea to provide in each test module a callable object that returns a | |
233 | pre-built test suite: | |
234 | ||
235 | <P> | |
236 | <div class="verbatim"><pre> | |
237 | def suite(): | |
238 | suite = unittest.TestSuite() | |
239 | suite.addTest(WidgetTestCase("testDefaultSize")) | |
240 | suite.addTest(WidgetTestCase("testResize")) | |
241 | return suite | |
242 | </pre></div> | |
243 | ||
244 | <P> | |
245 | or even: | |
246 | ||
247 | <P> | |
248 | <div class="verbatim"><pre> | |
249 | class WidgetTestSuite(unittest.TestSuite): | |
250 | def __init__(self): | |
251 | unittest.TestSuite.__init__(self,map(WidgetTestCase, | |
252 | ("testDefaultSize", | |
253 | "testResize"))) | |
254 | </pre></div> | |
255 | ||
256 | <P> | |
257 | (The latter is admittedly not for the faint-hearted!) | |
258 | ||
259 | <P> | |
260 | Since it is a common pattern to create a <tt class="class">TestCase</tt> subclass | |
261 | with many similarly named test functions, there is a convenience | |
262 | function called <tt class="function">makeSuite()</tt> that constructs a test suite | |
263 | that comprises all of the test cases in a test case class: | |
264 | ||
265 | <P> | |
266 | <div class="verbatim"><pre> | |
267 | suite = unittest.makeSuite(WidgetTestCase) | |
268 | </pre></div> | |
269 | ||
270 | <P> | |
271 | Note that when using the <tt class="function">makeSuite()</tt> function, the order in | |
272 | which the various test cases will be run by the test suite is the | |
273 | order determined by sorting the test function names using the | |
274 | <tt class="function">cmp()</tt> built-in function. | |
275 | ||
276 | <P> | |
277 | Often it is desirable to group suites of test cases together, so as to | |
278 | run tests for the whole system at once. This is easy, since | |
279 | <tt class="class">TestSuite</tt> instances can be added to a <tt class="class">TestSuite</tt> just | |
280 | as <tt class="class">TestCase</tt> instances can be added to a <tt class="class">TestSuite</tt>: | |
281 | ||
282 | <P> | |
283 | <div class="verbatim"><pre> | |
284 | suite1 = module1.TheTestSuite() | |
285 | suite2 = module2.TheTestSuite() | |
286 | alltests = unittest.TestSuite((suite1, suite2)) | |
287 | </pre></div> | |
288 | ||
289 | <P> | |
290 | You can place the definitions of test cases and test suites in the | |
291 | same modules as the code they are to test (such as <span class="file">widget.py</span>), | |
292 | but there are several advantages to placing the test code in a | |
293 | separate module, such as <span class="file">widgettests.py</span>: | |
294 | ||
295 | <P> | |
296 | ||
297 | <UL> | |
298 | <LI>The test module can be run standalone from the command line. | |
299 | </LI> | |
300 | <LI>The test code can more easily be separated from shipped code. | |
301 | </LI> | |
302 | <LI>There is less temptation to change test code to fit the code | |
303 | it tests without a good reason. | |
304 | </LI> | |
305 | <LI>Test code should be modified much less frequently than the | |
306 | code it tests. | |
307 | </LI> | |
308 | <LI>Tested code can be refactored more easily. | |
309 | </LI> | |
310 | <LI>Tests for modules written in C must be in separate modules | |
311 | anyway, so why not be consistent? | |
312 | </LI> | |
313 | <LI>If the testing strategy changes, there is no need to change | |
314 | the source code. | |
315 | </LI> | |
316 | </UL> | |
317 | ||
318 | <P> | |
319 | ||
320 | <DIV CLASS="navigation"> | |
321 | <div class='online-navigation'> | |
322 | <p></p><hr /> | |
323 | <table align="center" width="100%" cellpadding="0" cellspacing="2"> | |
324 | <tr> | |
325 | <td class='online-navigation'><a rel="prev" title="5.3.1 Basic example" | |
326 | href="node164.html"><img src='../icons/previous.png' | |
327 | border='0' height='32' alt='Previous Page' width='32' /></A></td> | |
328 | <td class='online-navigation'><a rel="parent" title="5.3 unittest " | |
329 | href="module-unittest.html"><img src='../icons/up.png' | |
330 | border='0' height='32' alt='Up One Level' width='32' /></A></td> | |
331 | <td class='online-navigation'><a rel="next" title="5.3.3 Re-using old test" | |
332 | href="legacy-unit-tests.html"><img src='../icons/next.png' | |
333 | border='0' height='32' alt='Next Page' width='32' /></A></td> | |
334 | <td align="center" width="100%">Python Library Reference</td> | |
335 | <td class='online-navigation'><a rel="contents" title="Table of Contents" | |
336 | href="contents.html"><img src='../icons/contents.png' | |
337 | border='0' height='32' alt='Contents' width='32' /></A></td> | |
338 | <td class='online-navigation'><a href="modindex.html" title="Module Index"><img src='../icons/modules.png' | |
339 | border='0' height='32' alt='Module Index' width='32' /></a></td> | |
340 | <td class='online-navigation'><a rel="index" title="Index" | |
341 | href="genindex.html"><img src='../icons/index.png' | |
342 | border='0' height='32' alt='Index' width='32' /></A></td> | |
343 | </tr></table> | |
344 | <div class='online-navigation'> | |
345 | <b class="navlabel">Previous:</b> | |
346 | <a class="sectref" rel="prev" href="node164.html">5.3.1 Basic example</A> | |
347 | <b class="navlabel">Up:</b> | |
348 | <a class="sectref" rel="parent" href="module-unittest.html">5.3 unittest </A> | |
349 | <b class="navlabel">Next:</b> | |
350 | <a class="sectref" rel="next" href="legacy-unit-tests.html">5.3.3 Re-using old test</A> | |
351 | </div> | |
352 | </div> | |
353 | <hr /> | |
354 | <span class="release-info">Release 2.4.2, documentation updated on 28 September 2005.</span> | |
355 | </DIV> | |
356 | <!--End of Navigation Panel--> | |
357 | <ADDRESS> | |
358 | See <i><a href="about.html">About this document...</a></i> for information on suggesting changes. | |
359 | </ADDRESS> | |
360 | </BODY> | |
361 | </HTML> |