Python 3 unittest simulates user input

How can I simulate user input in the middle of a function called by unit test (using Python 3 unittest)? For example, I have a function foo()

that I am testing. In a function, foo()

it asks for user input:

x = input(msg)

And the output is based on the input:

print("input: {0}".format(x))

I would like my unit test to run foo()

, inject input, and compare the output to the expected output.

+2


source to share


2 answers


I have this problem regularly when I try to test the code that brings up dialogs for user input and the same solution should work for both. You need to provide a new function associated with a name input

in your test scope with the same signature as the standard function input

, which simply returns a test value without actually asking the user. Depending on how your tests and code are set up, this injection can be done in several ways, so I'll leave it as an exercise for the reader, but your replacement method will be as simple as this:

def my_test_input(message):
  return 7

      

Obviously, you could also include content message

, if relevant, and return a data type of your choice. You can also do something more flexible and general, which allows you to reuse the same replacement method in multiple situations:

def my_test_input(retval, message):
  return retval

      



and then you add the partial function to input

:

import functools
test_input_a = functools.partial(my_test_input, retval=7)
test_input_b = functools.partial(my_test_input, retval="Foo")

      

We test_input_a

also leave test_input_b

as functions that take one argument message

, with an already bound argument retval

.

+7


source


Having difficulty testing certain components due to dependencies is usually a sign of poor design. Your function foo

should not depend on a global function input

, but rather on a parameter. Then, when you run the program in a production environment, you bundle things up so that the invoked foo

with the return result input

. Therefore, you foo

should read:

def foo(input):
    # do something with input

      



This will make testing easier. And by the way, if your tests have dependencies IO

, they are no longer modular, but rather functional. Check out the Misko Hevery Blog to learn more about testing.

+2


source







All Articles