Testing
# Sample code for our discussion on writing good test functions.
# Your test functions should include as many tests as necessary,
# but not more. Each test should have a reason to be there,
# covering some interesting edge case or scenario.
def testIsPrime():
# print "Testing isPrime()...",
assert(isPrime(-1) == False) # negative
assert(isPrime(0) == False) # zero
assert(isPrime(1) == False) # 1 is quite the special case
assert(isPrime(2) == True) # 2, only even prime
assert(isPrime(3) == True) # 3, smallest odd prime
assert(isPrime(4) == False) # 4, smallest even non-prime
assert(isPrime(9) == False) # 9, perfect square of odd prime
assert(isPrime(997) == True) # somewhat larger prime
# print "Passed!"
def workingIsPrime1(n):
if (n < 2): return False
for factor in xrange(2,n):
if (n % factor == 0):
return False
return True
def workingIsPrime2(n):
if (n == 2): return True
if ((n < 2) or (n % 2 == 0)): return False
for factor in xrange(2,int(round(n**0.5))+1):
if (n % factor == 0): return False
return True
def brokenIsPrime1(n):
# if (n < 2): return False # broken (commented out)
for factor in xrange(2,n):
if (n % factor == 0):
return False
return True
def brokenIsPrime2(n):
if (n < 1): return False # broken: 2 -> 1
for factor in xrange(2,n):
if (n % factor == 0):
return False
return True
def brokenIsPrime3(n):
if (n < 2): return False
for factor in xrange(2,n+1): # broken: n -> n+1
if (n % factor == 0):
return False
return True
def brokenIsPrime4(n):
if (n < 2): return False
for factor in xrange(2,n):
if (n % factor == 0):
return False
else: # broken: no "else", should be after loop
return True
def brokenIsPrime5(n):
if (n == 2): return True
if ((n < 2) or (n % 2 == 0)): return False
# for factor in xrange(2,int(round(n**0.5))+1):
for factor in xrange(2,int(round(n**0.5))): # broken, omitted +1
if (n % factor == 0): return False
return True
def raisesAssertion(f, *args):
# Helper fn for testing test function. You are responsible
# for what this function does, but not how it does it.
try: f(*args)
except AssertionError: return True
return False
def testTestIsPrime():
print "Testing testIsPrime()...",
global isPrime
# Store the "real" function so we can restore it after our tests
try: realIsPrime = isPrime
except: realIsPrime = None
# Now test our working and broken versions
isPrime = workingIsPrime1
assert(raisesAssertion(testIsPrime) == False)
isPrime = workingIsPrime2
assert(raisesAssertion(testIsPrime) == False)
isPrime = brokenIsPrime1
assert(raisesAssertion(testIsPrime) == True)
isPrime = brokenIsPrime2
assert(raisesAssertion(testIsPrime) == True)
isPrime = brokenIsPrime3
assert(raisesAssertion(testIsPrime) == True)
isPrime = brokenIsPrime4
assert(raisesAssertion(testIsPrime) == True)
isPrime = brokenIsPrime5
assert(raisesAssertion(testIsPrime) == True)
# And restore the "real" version
isPrime = realIsPrime
print "Passed!"
testTestIsPrime()
Debugging
# Sample code for our discussion on basic debugging techniques.
# The first example is correct (and probably should be ignored),
# and the next two have bugs in them.
#
# The keys to basic debugging are:
# 1) Find the simplest failure case possible
# (It is easier to trace smaller values...)
# 2) Add print statements copiously in your code
# (printing the values of relevant variables)
# 3) Carefully verify each line of the output,
# until you locate the error.
def longDivision(num, den):
# return num / den, by long division
# only for non-negative num and positive den
assert((num >= 0) and (den > 0))
result = 0
remainder = 0
for k in xrange(digitCount(num)-1, -1, -1):
remainder = 10*remainder + kthDigit(num, k)
result += remainder/den * 10**k
remainder %= den
return (result, remainder)
def longDivision1(num, den):
# return num / den, by long division
# only for non-negative num and positive den
assert((num >= 0) and (den > 0))
result = 0
remainder = 0
for k in xrange(digitCount(num), 0, -1):
print "k=", k
remainder = 10*remainder + kthDigit(num, k)
result += remainder/den * 10**k
remainder %= den
print "remainder=", remainder
return (result, remainder)
print longDivision1(50, 5) # (10, 0), works!
print longDivision1(1234, 72) # (10, 51) but should be (17, 10), fails!
def longDivision2(num, den):
# return num / den, by long division
# only for non-negative num and positive den
assert((num >= 0) and (den > 0))
result = 0
remainder = 0
for k in xrange(digitCount(den)-1, -1, -1):
remainder = 10*remainder + kthDigit(num, k)
result += remainder/den * 10**k
remainder %= den
return (result, remainder)
print longDivision2(50, 10) # (5, 0), works!
print longDivision2(1234, 72) # (0, 34) but should be (17, 10), fails!
def testLongDivision():
print "Testing longDivision()...",
for x in xrange(0,100):
for y in xrange(1, 100):
assert(longDivision(x, y) == (x/y, x%y))
print "passed!"
testLongDivision()