Testing
Take a simple function
def factorial(n):
total = 1
while n > 1:
total = total * n
n = n - 1
return total
Test method 1: call the function
Just call the function a few times with different values and observe the output:
print factorial(0)
print factorial(1)
print factorial(2)
print factorial(3)
Expect the output:
1
1
2
6
Test method 2: simple boolean tests
Create expressions that call the function and each time compare it to the expected output:
print factorial(0) == 1
print factorial(1) == 1
print factorial(2) == 2
print factorial(3) == 6
Expect:
True
True
True
True
If any of these tests return False
, you will not know the value that they return and you will need to investigate further, but this introduces the idea of a test that either passes, returning True
, or fails, returning False
. Unlike the first test method, these are self-contained tests that tell you at a glance whether or not the function is returning the correct value.
Interlude: Assertions
Assertions are commonly used inside functions to test for errors, like this:
def factorial(n):
assert n >= 0
total = 1
while n > 1:
total = total * n
n = n - 1
return total
In this case, the program will terminate if you attempt to evaluate the factorial of a negative number.
Assertions are a useful addition to the process of testing your code, but are not a replacement for creating separate tests outside your functions.
Test method 3: The “Udacity” method
def test():
test_cases = [(0,1),
(1,1),
(2,2),
(3,6)]
for (arg, answer) in test_cases:
result = factorial(arg)
if result != answer:
print "Test with data:", arg, "failed with result ", result
else:
print "Test case passed!"
test()
This has the advantages over simple one-line assertions, of allowing you to easily add new test cases and of allowing you to print more information when a test fails.
Test method 4: unittest
unitest
is the standard Python unit testing framework.
import unittest
class FactorialTest(unittest.TestCase):
def test(self):
self.assertEqual(factorial(0), 1)
self.assertEqual(factorial(1), 1)
self.assertEqual(factorial(2), 2)
self.assertEqual(factorial(3), 6)
if __name__ == '__main__':
unittest.main()
You can return to this after we have looked at object-oriented programming, when class
and self
will make more sense.
Test method 5: doctest
def factorial(n):
"""Return the factorial of n, an exact integer >= 0
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
total = 1
while n > 1:
total = total * n
n = n - 1
return total
if __name__ == "__main__":
import doctest
doctest.testmod()
You can write human-readable comments in your code, which with the magic of >>>
, will execute the code in your comments and check that the output is the same as following line.
Other methods
This quick summary does not even begin to exhaust the possible ways of testing in Python. As your applications gets more complex, other testing libraries are available to help you manage that complexity. If you are curious, take a look at pytest
, nose
, tox
, unittest2
and mock
.