2. How to unit test
• Not manually, that's for sure
• You write code that exercises your code
• Perform assertions that record
o that you get the results you expect for various inputs
o that exceptions are raised when they should be
• Pay attention to edge cases
3. Test-driven development
• Write some tests (yes, first)
• Run them
o They will fail because the code isn't written yet. That
is supposed to happen. Good news is you will know
the tests run.
• Write some code
• Now run the tests again
• Work until the tests pass
• Iterate!
4. Unit testing in Python
• The module unittest is already there
• Docs
• Python 2.7
• Python 3
• Also see
• The unit testing chapter from Dive Into
Python
• Are there alternatives to unittest? See what
they say on StackOverflow
5. A first example
• Let's write a function to interleave two lists
• It will be okay if one list is longer than the
other
• Before we start writing the code, we should
know what the function should produce for all
types of inputs:
interleave([], []) ☞ []
interleave([1,5,3], ["hello"]) ☞
[1,"hello",5,3]
interleave([True], [[], 8]) ☞ [True, [],
8]
6. Write the test first(interleavetest.py)
from interleave import interleave
import unittest
class TestGettingStartedFunctions(unittest.TestCase):
def test_interleave(self):
cases = [
([], [], []),
([1, 4, 6], [], [1, 4, 6]),
([], [2, 3], [2, 3]),
([1], [9], [1, 9]),
([8, 8, 3, 9], [1], [8, 1, 8, 3, 9]),
([2], [7, 8, 9], [2, 7, 8, 9]),
]
for a, b, expected in cases:
self.assertEqual(interleave(a, b), expected)
7. Write a stub (interleave.py)
def interleave(a, b):
return None
8. Run the test
$ python interleavetest.py
F
======================================================================
FAIL: test_interleave (__main__.TestGettingStartedFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
File "interleavetest.py", line 15, in test_interleave
self.assertEqual(interleave(a, b), expected)
AssertionError: None != []
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
9. Now write the code
def interleave(a, b):
"""Return the interleaving of two sequences as a list."""
return [y for x in izip_longest(a, b) for y in x if y is not None]
10. Test again
$ python interleavetest.py
E
======================================================================
ERROR: test_interleave (__main__.TestGettingStartedFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
File "interleavetest.py", line 15, in test_interleave
self.assertEqual(interleave(a, b), expected)
File "/Users/raytoal/scratch/interleave.py", line 3, in interleave
return [y for x in izip_longest(a, b) for y in x if y is not None]
NameError: global name 'izip_longest' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
11. Fix the code
from itertools import izip_longest
def interleave(a, b):
"""Return the interleaving of two sequences as a list."""
return [y for x in izip_longest(a, b) for y in x if y is not None]
12. Rerun the test
$ python interleavetest.py
.
-------------------------------------------------------------
Ran 1 test in 0.000s
OK