简体   繁体   English

在 Python 3 中使用 unittest.mock 修补 input()

[英]Using unittest.mock to patch input() in Python 3

How do you use the @patch decorator to patch the built-in input() function?你如何使用@patch 装饰器来修补内置的 input() 函数?

For example, here's a function in question.py that I'd like to test, which contains a call to 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")

Here's my test, which gives me the error "ImportError: No module named ' builtins '":这是我的测试,它给了我错误“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)

__builtin__ module is renamed to builtins in Python 3. Replace as follow: __builtin__模块在 Python 3 中重命名为builtins 。替换如下:

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

UPDATE更新

input has an optional parameter. input有一个可选参数。 updated the code to accept the optional parameter.更新了代码以接受可选参数。

Or use Mock's return_value attribute.或者使用 Mock 的return_value属性。 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
>>>

For Python 2.x:对于 Python 2.x:

@patch('__builtin__.input')

worked for me.为我工作。

For Python 3.8 the accepted answer didn't work for me.对于 Python 3.8,接受的答案对我不起作用。 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.不确定我是否做错了什么,但你在这里。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM