| 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> |