[Tutor] how to unittest cli input

Danny Yoo dyoo at hashcollision.org
Tue Oct 13 21:11:43 CEST 2015


On Sat, Oct 10, 2015 at 5:41 PM, Alex Kleider <akleider at sonic.net> wrote:
> """
> I'm trying to follow a test driven development paradigm (using
> unittest) but can't figure out how to test functions that collect
> info from the command line such as the following.
> """
> # collect.py
> def collect_data():
>     ret = {}
>     ret['first'] = input("Enter your first name: ")
>     ret['last'] = input("Enter your last name: ")
>     ret['phone'] = input("Your mobile phone #: ")
>     return ret


Hi Alex,


If we look at collect_data in a funny way, we might see that it is a
"function" because it's parameterized by the behavior of the
interactive input() function.  That means that we can make it a pure
function by explicitly treating "input" as a parameter.

#########################################
def collect_data(ask):
    ret = {}
    ret['first'] = ask("Enter your first name: ")
    ret['last'] = ask("Enter your last name: ")
    ret['phone'] = ask("Your mobile phone #: ")
    return ret
#########################################


Making it an explicit parameter means that, when we call it, we can
feed it input() as the ask()er:

######################
def main():
    print(collect_data(input))
######################


It also means that we can pass in an ask()er that is non-interactive,
which is good for unit tests. For example, here's one we can build up
quickly:

######################
def make_ask(f, l, p):
    d = {'Enter your first name: ' : f,
           'Enter your last name: ' : l,
           'Your mobile phone #: ' : p}
    return d.get
######################


What does this do?  It gives us an ask that knows how to respond to
those questions.  For example, at the interactive prompt:

##########################################
>>> ask = make_ask('jane', 'doe', '123456789')
>>> ask('Enter your first name: ')
'jane'
>>> ask('Enter your last name: ')
'doe'
##########################################


And now this is a tool we can use for unit testing the behavior of
collect_data.  That is, we can say:

    collect_data(make_ask('jane', 'doe', '12345'))

and know that we expect the dictionary value:

    {'first': 'jane', ...}


The key is to look at interaction as an explicit parameter of your
function: once it's a parameter, then you can pass in custom
interactions that are controlled by your unit test.


More information about the Tutor mailing list