20

How do you use the @patch decorator to patch the built-in input() function?

For example, here's a function in question.py that I'd like to test, which contains a call to input():

def query_yes_no(question, default="yes"):
""" Adapted from http://stackoverflow.com/questions/3041986/python-command-line-yes-no-input """
 valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
 if default is None:
 prompt = " [y/n] "
 elif default == "yes":
 prompt = " [Y/n] "
 elif default == "no":
 prompt = " [y/N] "
 else:
 raise ValueError("invalid default answer: '%s'" % default)
 while True:
 sys.stdout.write(question + prompt)
 choice = input().lower()
 if default is not None and choice == '':
 return valid[default]
 elif choice in valid:
 return valid[choice]
 else:
 sys.stdout.write("Please respond with 'yes' or 'no' "
 "(or 'y' or 'n').\n")

Here's my test, which gives me the error "ImportError: No module named 'builtins'":

import unittest
from unittest.mock import patch
import question
class TestQueryYesNo(unittest.TestCase):
 @patch('__builtins__.input.return_value', 'y')
 def test_query_y(self):
 answer = question.query_yes_no("Blah?")
 self.assertTrue(answer)
asked Aug 10, 2013 at 11:16

5 Answers 5

36

__builtin__ module is renamed to builtins in Python 3. Replace as follow:

@patch('builtins.input', lambda *args: 'y')

UPDATE

input has an optional parameter. updated the code to accept the optional parameter.

answered Aug 10, 2013 at 11:24
Sign up to request clarification or add additional context in comments.

3 Comments

@IlanBiala, It works for me: ideone.com/kdAjEd (tested on Python 3.5.1, Ubuntu 16.04 beta, WIndows 7, simplified for brevity)
input takes one positional argument, so: @patch('builtins.input', lambda _ : 'y')
@SeF, Thank you for the comment. input's argument is optional; so I used *args instead of _.
8

Or use Mock's return_value attribute. I couldn't get it to work as a decorator, but here's how to do it with a context manager:

>>> import unittest.mock
>>> def test_input_mocking():
... with unittest.mock.patch('builtins.input', return_value='y'):
... assert input() == 'y'
...
>>> def test_input_mocking():
... with unittest.mock.patch('builtins.input', return_value='y'):
... assert input() == 'y'
... print('we got here, so the ad hoc test succeeded')
...
>>> test_input_mocking()
we got here, so the ad hoc test succeeded
>>>
answered May 26, 2016 at 17:51

Comments

1

For Python 2.x:

@patch('__builtin__.input')

worked for me.

Brad Solomon
41.3k39 gold badges168 silver badges261 bronze badges
answered Aug 25, 2017 at 18:12

Comments

0

For Python 3.8 the accepted answer didn't work for me. It didn't like the positional parameter even though my code was actually utilizing it. What worked for me was simply:

@patch('builtins.input')

Not sure if I am doing something wrong, but here you are.

answered Jul 31, 2020 at 16:08

Comments

0

In my test I wanted to pass many different inputs to test match inside run, and It's works fine. Test passed.

import io
import unittest
from unittest.mock import patch
from TextApp import run
def input_args():
 yield "show"
 yield "switch ts1"
 yield "show"
 yield "exit"
class TestTextApp(unittest.TestCase):
 @patch("builtins.input", side_effect=input_args())
 def test_ShowSwitchTS1ShowExit(self, mock_input):
 expected = (
 "ToggleSwitch is: off\n"
 "ToggleSwitch is: off\n"
 "ToggleSwitch is: off\n"
 "LightBulb is: off\n"
 "ToggleSwitch is: on\n"
 "ToggleSwitch is: off\n"
 "ToggleSwitch is: off\n"
 "LightBulb is: on\n"
 )
 with patch("sys.stdout", new=io.StringIO()) as fake_out:
 run()
 result = fake_out.getvalue()
 self.assertEqual(expected, result)
answered May 11, 2024 at 18:55

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.