In most cases, this strategy is applicable, wise, and encouraged!
Example: Solution to Deitel exercise 4.4c): Write a function that determines whether a number is a prime. Let's call it is_prime.
Here is a first solution (which might be saved in a file called
ex4_4.py - see this tip):
import math
def is_prime(c):
for i in range(2, int(math.sqrt(c))):
if c%i == 0:
return 0
return 1
def test_function():
# list of input/output tuples:
inout = [(2, 1), (5, 1), (7, 1), (19, 1), (31, 1), (137, 1), (881, 1),
(9, 0), (14, 0), (77, 0), (100, 0), (169, 0)]
for input, output in inout:
if is_prime(input) != output:
print "oops: input %d gave wrong output" %input
if __name__=="__main__":
test_function()
Now we run the program and get this result:
oops: input 9 gave wrong outputHmm.. what is wrong with the above code? Well, 9 and 169 are quadratic numbers, do we check for their squareroots 3 and 13? Looking closely at the code we remember that the range(a, b) function includes a but not b in the resulting list, and so we don't actually test in is_prime whether the squareroot of n is a divisor. Thus we modify this line to:
oops: input 169 gave wrong output
for i in range(2, 1+int(math.sqrt(n))):
Of course we keep 9 and 169 (and the other numbers) in the test. For some functions we might discover special cases. These should go in the test - and stay there in case we change the function's implementation and need to run the test again.