I have a console program written in Python. It asks the user questions using the command:
some_input = input('Answer the question:', ...)
How would I test a function containing a call to input
using pytest
? I wouldn't want to force a tester to input text many many times only to finish one test run.
If you want to number input or input in other data types, you need to perform type conversion on the input value. Let's understand this with an example. As you know whatever you enter as input, the input() function always converts it into a string. Read How to check if user input is a number or string.
To ask for user input in Python, use the built-in input() function. In addition to asking for simple string input like this, you also want to learn how to: Ask for multiple inputs in one go. Ask for input again until a valid input is given.
The input() function converts all the user input to a string even if that's the number. User can enter Unicode characters as well, as shown below.
The input() function allows a user to insert a value into a program. input() returns a string value. You can convert the contents of an input using any data type.
As The Compiler suggested, pytest has a new monkeypatch fixture for this. A monkeypatch object can alter an attribute in a class or a value in a dictionary, and then restore its original value at the end of the test.
In this case, the built-in input
function is a value of python's __builtins__
dictionary, so we can alter it like so:
def test_something_that_involves_user_input(monkeypatch): # monkeypatch the "input" function, so that it returns "Mark". # This simulates the user entering "Mark" in the terminal: monkeypatch.setattr('builtins.input', lambda _: "Mark") # go about using input() like you normally would: i = input("What is your name?") assert i == "Mark"
You should probably mock the built-in input
function, you can use the teardown
functionality provided by pytest
to revert back to the original input
function after each test.
import module # The module which contains the call to input class TestClass: def test_function_1(self): # Override the Python built-in input method module.input = lambda: 'some_input' # Call the function you would like to test (which uses input) output = module.function() assert output == 'expected_output' def test_function_2(self): module.input = lambda: 'some_other_input' output = module.function() assert output == 'another_expected_output' def teardown_method(self, method): # This method is being called after each test case, and it will revert input back to original function module.input = input
A more elegant solution would be to use the mock
module together with a with statement
. This way you don't need to use teardown and the patched method will only live within the with
scope.
import mock import module def test_function(): with mock.patch.object(__builtins__, 'input', lambda: 'some_input'): assert module.function() == 'expected_output'
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