[Tutor] unit testing raw_input()

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Wed Apr 19 03:39:29 CEST 2006



On Tue, 18 Apr 2006, Andre Roberge wrote:

> Suppose I had a function like the following:
>
> def y_n(prompt="Answer yes or no"):
>    while True:
>        answer = raw_input(prompt)
>        if answer in ['y', 'Y', 'yes']:
>            print "You said yes!"
>            break
>        elif answer in ['n', 'N', 'no']:
>            print "You said no!"
>            break
>        else:
>            print "%s is an invalid answer."%answer
>
> How could I go about to write an automated test for it?


Hi Andre,

One way to do this is to parameterize y_n() a little more to make it more 
amendable to unit testing.


If we look at y_n(), we'd say that "raw_input()" is a free variable in 
here --- its meaning comes from the outside environment as part of 
builtins.  We can change this by making it an explicit parameter:

########################################################
def y_n(prompt="Answer yes or no", raw_input=raw_input):
     while True:
         answer = raw_input(prompt)
         if answer in ['y', 'Y', 'yes']:
             print "You said yes!"
             break
         elif answer in ['n', 'N', 'no']:
            print "You said no!"
             break
         else:
             print "%s is an invalid answer."%answer
########################################################

Looks a little funny.  *grin*


But now we can hardcode particular inputs by sending y_n() a mock 
"raw_input" that returns precooked values.

###########################
def yes1_raw_input(prompt):
     return "y"

def yes2_raw_input(prompt):
     return "Y"

def yes3_raw_input(prompt):
     return "yes"

def yes4_raw_input(prompt):
     return "YES"
###########################

And then we can use these as part of our test case:

     y_n(raw_input=yes1_raw_input)



We can also parameterize output in the same way.  Right now, the function 
is printing out the answer.  Testing printed output is a little harder in 
Python without fiddling around with stdout, but we can also make this also 
a parameter of the function:

###################################################
def y_n(prompt="Answer yes or no",
         raw_input=raw_input,
         output=sys.stdout):
     while True:
         answer = raw_input(prompt)
         if answer in ['y', 'Y', 'yes']:
             print >>output, "You said yes!"
             break
         elif answer in ['n', 'N', 'no']:
             print >>output, "You said no!"
             break
         else:
             print >>output, "%s is an invalid answer."%answer
###################################################


Now we can inject our own output string that we can use to test what has 
happened:

     ## pseudocode

     import StringIO
     test_output = StringIO.StringIO()
     y_n(raw_input = yes4_raw_input,
         output = test_output)

     assertEquals("You said yes!", test_output.getvalue())

Does this make sense so far?  y_n() in its original form might not be in 
the right shape to make it easy to test, but we can turn it into a form 
that is more easily testable.


Good luck!


More information about the Tutor mailing list