如何使用pytestmonkeypatch模拟两个连续的控制台输入 [英] How to simulate two consecutive console inputs with pytest monkeypatch

查看:46
本文介绍了如何使用pytestmonkeypatch模拟两个连续的控制台输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果第一个用户输入的回答是n",则模块overwrite_file"(参见代码示例)要求输入新文件名

The module "overwrite_file" (see code example) asks for input of a new filename if the first user input is answered with "n"

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

In my test setup I use two consecutive monkeypatch.setattr calls to simulate the input. The result is an endless loop if i use the order as follws:

monkeypatch.setattr('builtins.input', lambda overwrite: "n")
monkeypatch.setattr('builtins.input', lambda new_name: new_filename)

第二个monkeypatch.setattr 调用被激活并且'new.pkl' 被分配给变量overwrite.

The second monkeypatch.setattr call is activated and 'new.pkl' is assigned to the variable overwrite.

如果我改变monkeypatch命令的顺序:

If I change the order of the monkeypatch commands as so:

monkeypatch.setattr('builtins.input', lambda new_name: new_filename)
monkeypatch.setattr('builtins.input', lambda overwrite: "n")

我收到一个 AssertionError 因为 'n' 被分配给变量 new_name 并创建了一个名为n"的文件.

I get an AssertionError as 'n' is assigned to the variable new_name and a file calld "n" is created.

如何获得预期的测试功能?

How do I get the intended test functionality?

解释器:Python 3.8

Interpreter: 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会战胜所有其他的,所以input(f"overwrite {filename} (y/n): ") 正在获取 "n"input("new filename:") 也是如此.为了以正确的顺序提供所需的输入,我们可以对一个循环响应的方法进行猴子补丁

The last monkeypatch will win out against all the others, so input(f"overwrite {filename} (y/n): ") is getting "n", and so is input("new filename: "). To provide the desired inputs in the correct order, we can monkeypatch a method that will cycle its responses

responses = iter(['n', new_filename])
monkeypatch.setattr('builtins.input', lambda msg: next(responses))

请注意,responses 是一个迭代器对象——也就是说,对它调用 next() 将返回列表中的下一项.如果 input() 被调用的次数多于列表中的项目数,StopIteration 将被引发.可以提供可选的默认值,避免 StopIteration 异常,并允许永远调用 input():

Note that responses is an iterator object — that is, calling next() on it will return the next item in the list. If input() is called more times than there are items in the list, StopIteration will be raised. An optional default value may be provided, avoiding the StopIteration exception, and allowing input() to be called forever and ever:

next(responses, '\n')

可能有一种更简洁的方式为 input() 提供标准输入,但我现在不知所措.

There may be a cleaner way to provide stdin to input(), but I'm at a loss at the moment.

这篇关于如何使用pytestmonkeypatch模拟两个连续的控制台输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆