Python 3.x 如何使用pytest monkeypatch模拟两个连续的控制台输入

Python 3.x 如何使用pytest monkeypatch模拟两个连续的控制台输入,python-3.x,tdd,pytest,Python 3.x,Tdd,Pytest,如果第一个用户输入回答为n,则模块overwrite_file see code example要求输入新文件名 在我的测试设置中,我使用两个连续的monkeypatch.setattr调用来模拟输入。 如果我使用以下顺序,结果是一个无止境的循环: monkeypatch.setattr('builtins.input', lambda overwrite: "n") monkeypatch.setattr('builtins.input', lambda new_name: new_filen

如果第一个用户输入回答为n,则模块overwrite_file see code example要求输入新文件名

在我的测试设置中,我使用两个连续的monkeypatch.setattr调用来模拟输入。 如果我使用以下顺序,结果是一个无止境的循环:

monkeypatch.setattr('builtins.input', lambda overwrite: "n")
monkeypatch.setattr('builtins.input', lambda new_name: new_filename)
第二个monkeypatch.setattr调用被激活,并且“new.pkl”被分配给变量overwrite

如果我将monkeypatch命令的顺序更改为:

monkeypatch.setattr('builtins.input', lambda new_name: new_filename)
monkeypatch.setattr('builtins.input', lambda overwrite: "n")
当'n'被分配给变量new_name并创建一个名为n的文件时,我会得到一个断言错误

如何获得预期的测试功能

解释器:Python 3.8

from os.path import exists, join, dirname
import pickle
import pytest


def overwrite_file(filename):
    # loop until overwrite existing file or input of a file name which does not exist
    dump_file = False
    while not dump_file:
        if exists(filename):
            overwrite = input(f"overwrite {filename} (y/n): ")
            if overwrite in ["y", "Y"]:
                dump_file = True
            if overwrite in ["n", "N"]:
                new_name = input("new filename: ")
                filename = join(dirname(filename), new_name)
        else:
            dump_file = True

    return filename


@pytest.fixture()
def pickle_test_env(tmpdir_factory):
    a_dir = tmpdir_factory.mktemp('src_dir')
    a_file = a_dir.join('already_there.pkl')
    with open(a_file, "wb") as f:
        pickle.dump({"C": 27.1, "S": -8.2, "T": 29.7}, f)
    return a_dir


def test_new_filename_if_file_exists(pickle_test_env, monkeypatch):
    """ is overwrite_file returning a valid new filename if filename exists
    and should not be overwritten? """
    filename = 'already_there.pkl'
    new_filename = 'new.pkl'
    assert exists(join(pickle_test_env, filename))
    monkeypatch.setattr('builtins.input', lambda new_name: new_filename)
    monkeypatch.setattr('builtins.input', lambda overwrite: "n")
    assert overwrite_file(join(pickle_test_env, filename)) == join(pickle_test_env, new_filename)

最后一个monkeypatch将战胜所有其他的monkeypatch,因此inputfoverwrite{filename}y/n:得到了n,inputnew filename:也得到了n。为了以正确的顺序提供所需的输入,我们可以使用monkeypatch方法循环其响应

responses = iter(['n', new_filename])
monkeypatch.setattr('builtins.input', lambda msg: next(responses))
请注意,responses是一个迭代器对象——也就是说,对其调用next将返回列表中的下一项。如果调用输入的次数超过列表中的项目,则将引发StopIteration。可以提供可选的默认值,避免StopIteration异常,并允许永远调用输入:

next(responses, '\n')

也许有一种更干净的方法可以为输入提供stdin,但我现在不知所措。

最后一个monkeypatch将战胜所有其他的monkeypatch,因此inputfoverwrite{filename}y/n:得到了n,inputnew filename:。为了以正确的顺序提供所需的输入,我们可以使用monkeypatch方法循环其响应

responses = iter(['n', new_filename])
monkeypatch.setattr('builtins.input', lambda msg: next(responses))
请注意,responses是一个迭代器对象——也就是说,对其调用next将返回列表中的下一项。如果调用输入的次数超过列表中的项目,则将引发StopIteration。可以提供可选的默认值,避免StopIteration异常,并允许永远调用输入:

next(responses, '\n')
也许有一种更干净的方法可以为输入提供stdin,但我现在不知所措