Tip
Unit testing is essential
When in doubt, design the tests first. Fit the code to the test cases.
Python offers two built-in testing frameworks. Most applications and libraries will make use of both. The general wrapper for all testing is the unittest
module. In addition, many public API docstrings will have examples that can be found and used by the doctest
module. Also, unittest
can incorporate modules of doctest
.
One lofty ideal is that every class and function has at least a unit test. More importantly, visible classes, functions, and modules will have doctest
too. There are other lofty ideals: 100 percent code coverage, 100 percent logic path coverage, and so on.
Pragmatically, some classes don't need testing. A class created by namedtuple()
, for example, doesn't really need a unit test, unless you don't trust the namedtuple()
implementation in the first place. If you don't trust your Python implementation, you can't really write applications with it.
Generally, we want to develop the test cases first and then write code that fits these test cases. The test cases formalize the API for the code. This book will reveal numerous ways to write code that has the same interface. This is important. Once we've defined an interface, there are still numerous candidate implementations that fit the interface. One set of tests should apply to several different object-oriented designs.
One general approach to using the unittest
tools is to create at least three parallel directories for your project as follows:
myproject
: This directory is the final package that will be installed inlib/site-packages
for your package or application. It has an__init__.py
package, and we'll put our files in here for each module.test
: This directory has the test scripts. In some cases, the scripts will parallel the modules. In some cases, the scripts may be larger and more complex than the modules themselves.doc
: This directory has other documentation. We'll touch on this in the next section as well as in Chapter 18, Quality and Documentation.
In some cases, we'll want to run the same test suite on multiple candidate classes so that we can be sure that each candidate works. There's no point in doing timeit
comparisons on code that doesn't actually work.