How can I simulate user input in the middle of a function called by a unit test (Using Python 3's unittest)? For example, I have a function foo()
who's output I'm testing. In the foo()
function, 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()
, enter an input and compare the result with the expected result.
Having difficulties in testing some component because of dependencies it's usually a sign of bad design. Your foo
function should not depend on the global input
function, but rather on a parameter. Then, when you run the program in a production environment, you wire the things in such a way that the foo
is called with the result of what input
returns. So foo
should read:
def foo(input):
# do something with input
This will make testing much more easier. And by the way, if your tests have IO
dependencies they're no longer unit tests, but rather functional tests. Have a look on Misko Hevery's blog for more insights into testing.
I have this problem regularly when I'm trying to test code that brings up dialogs for user input, and the same solution should work for both. You need to provide a new function bound to the name input
in your test scope with the same signature as the standard input
function which just returns a test value without actually prompting the user. Depending on how your tests and code are setup this injection can be done in a number of ways, so I'll leave that as an exercise for the reader, but your replacement method will be something simple like:
def my_test_input(message):
return 7
Obviously you could also switch on the contents of message
if that were relevant, and return the datatype of your choice of course. You can also do something more flexible and general that allows for reusing the same replacement method in a number of situations:
def my_test_input(retval, message):
return retval
and then you would inject a partial function into input
:
import functools
test_input_a = functools.partial(my_test_input, retval=7)
test_input_b = functools.partial(my_test_input, retval="Foo")
Leaving test_input_a
and test_input_b
as functions that take a single message
argument, with the retval
argument already bound.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With