19

你如何使用@patch 装饰器来修补内置的 input() 函数?

例如,这是我想测试的 question.py 中的一个函数,其中包含对 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")

这是我的测试,它给了我错误“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)
4

4 回答 4

32

__builtin__模块在 Python 3 中被重命名为builtins。替换如下:

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

更新

input有一个可选参数。更新了代码以接受可选参数。

于 2013-08-10T11:24:49.653 回答
7

或者使用 Mock 的return_value属性。我无法让它作为装饰器工作,但这是使用上下文管理器的方法:

>>> 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
>>>
于 2016-05-26T17:51:59.780 回答
1

对于 Python 2.x:

@patch('__builtin__.input')

为我工作。

于 2017-08-25T18:12:03.650 回答
0

对于 Python 3.8,接受的答案对我不起作用。即使我的代码实际上正在使用它,它也不喜欢位置参数。对我有用的只是:

@patch('builtins.input')

不知道我是否做错了什么,但你在这里。

于 2020-07-31T16:08:39.057 回答