如何测试内部有两个或多个 input() 的函数?

How to test function, that has two or more input()'s inside?

我需要测试一些 python 3 代码,但我在测试函数时遇到了一些 input() 的问题。

示例:

def two_answers():
    if input("Input 'go' to proceed") != "go":
        return two_answers()
    else:
        while input("Input 'bananas' to proceed") != "bananas":
            print("What?!")
    print("You've just gone bananas!")

对于只有一个输入的函数,我使用:

def test_some_function(self):
    codefile.input = lambda x: 'u'
    codefile.some_function() . . . .

然后:

def teardown_method(self, method):
    codefile.input = input

还原输入。

但是这里不行。求助!

你想要的是模拟用户输入。

您必须使用 unittest.mock 并修补 input 函数。

参见Quick Guide

这是我的解决方案:

class SimulatedInput:

    def __init__(self,*args):
        self.args = iter(args) 

    def __call__(self,x):
        try:
            return next(self.args)
        except StopIteration:
            raise Exception("No more input")

然后你就可以像以前一样使用它了:

def test_some_function(self):
    codefile.input = SimulatedInput("u","v")
    codefile.some_function() . . . .

一个没有依赖项的简约示例。随心所欲地使用它来扩展它:

import sys
import io

def two_answers():
    if input("Input 'go' to proceed") != "go":
        return two_answers()
    else:
        while input("Input 'bananas' to proceed") != "bananas":
            print("What?!")
    print("You've just gone bananas!")

def wrapper():
    lines = ["go", "bananas"]
    def fake_input(*args, **kwargs):
        return lines.pop(0)
    global input
    real_input = input
    input = fake_input
    two_answers()
    input = real_input


wrapper()

我会将输入包装到一个函数中。

def input_wrap(prompt):
  return input(prompt)

然后就可以注射了

def two_answers(input_func):
  if input_func('...') != 'go':
    return two_answers(input_func)
  ...

现在当你想测试它时,你可以注入假的或模拟的:

def test_two_answers(self):
  fake_input = mock.MagicMock()
  fake_input.side_effect = ['go', 'foo', 'bananas']
  two_answers(fake_input) # no assertion for needed since there's no return value

稍后在执行 two_answers 的代码中,您可以这样称呼它:

two_answers(input_wrap)