How do I test the STDOUT output of a Python script with a testing framework like doctest, unittest, nose, etc? For example, say running my script "todo.py --list" shou
Here is something that I wrote one evening that tests script runs. Note that the test does cover the basic cases, but it is not thorough enough to be a unittest by itself. Consider it a first draft.
import sys
import subprocess
if sys.platform == "win32":
cmd = "zs.py"
else:
cmd = "./zs.py"
def testrun(cmdline):
try:
retcode = subprocess.call(cmdline, shell=True)
if retcode < 0:
print >>sys.stderr, "Child was terminated by signal", -retcode
else:
return retcode
except OSError, e:
return e
tests = []
tests.append( (0, " string pattern 4") )
tests.append( (1, " string pattern") )
tests.append( (3, " string pattern notanumber") )
passed = 0
for t in tests:
r = testrun(cmd + t[1])
if r == t[0]:
res = "passed"
passed += 1
else:
res = "FAILED"
print res, r, t[1]
print
if passed != len(tests):
print "only",passed,"tests passed"
else:
print "all tests passed"
And here is the script that was being tested, zs.py, This does pattern searches in a string similar to the way biochemists search for patterns in DNA data or protein chain data.
#!/usr/bin/env python
# zs - some example Python code to demonstrate to Z??s
# interviewers that the writer really does know Python
import sys
from itertools import *
usage = '''
Usage: zs "
print top n matches of pattern in substring"
'''
if sys.hexversion > 0x03000000:
print "This script is only intended to run on Python version 2"
sys.exit(2)
if len(sys.argv) != 4:
print usage
sys.exit(1)
A = sys.argv[1] # string to be searched
B = sys.argv[2] # pattern being searched for
N = sys.argv[3] # number of matches to report
if not N.isdigit():
print " must be a number"
print usage
sys.exit(3)
def matchscore(s1, s2):
''' a helper function to calculate the match score
'''
matches = 0
for i in xrange(len(s1)):
if s1[i] == s2[i]:
matches += 1
return (matches + 0.0) / len(s1) # added 0.0 to force floating point div
def slices(s, n):
''' this is a generator that returns the sequence of slices of
the input string s that are n characters long '''
slen = len(s)
for i in xrange(slen - n + 1):
yield s[i:i+n]
matchlen = len(B)
allscores = ((matchscore(x,B),x,i) for i,x in enumerate(slices(A,matchlen)))
nonzeros = [ y for y in allscores if y[0] != 0 ]
for elem in sorted(nonzeros,key=lambda e: e[0],reverse=True):
nprinted = 0 # We will count them; in case num elements > N
print elem[1], str(round(elem[0],4)), elem[2]
nprinted += 1
if nprinted >= N:
break