python-3.x - 如何使用 pytestmonkeypatch 模拟两个连续的控制台输入

标签 python-3.x tdd pytest

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

在我的测试设置中,我使用两个连续的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")

我得到一个 AssertionError 因为 '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)

最佳答案

最后一个猴子补丁将战胜所有其他的,所以 input(f"overwrite {filename} (y/n): ")正在获取 "n"input("new filename: ") 也是如此.为了以正确的顺序提供所需的输入,我们可以使用monkeypatch一个方法来循环其响应

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

请注意 responses是一个迭代器对象——即调用 next()它将返回列表中的下一个项目。如 input()被调用的次数多于列表中的项目数,StopIteration将被提升。可以提供可选的默认值,避免 StopIteration异常(exception),并允许 input()永远被称为:
next(responses, '\n')

可能有一种更简洁的方式将 stdin 提供给 input() ,但我现在不知所措。

关于python-3.x - 如何使用 pytestmonkeypatch 模拟两个连续的控制台输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59986625/

相关文章:

python - 为什么我的 python 打印比 Go 的 fmt.Print 和 os.Stdout.Write 运行得更快

python - “str_iterator”对象不可调用

django - 为什么 __unicode__ 不起作用而 __str__ 起作用?

python - 在 gitlab CI/CD 中使用 selenium

python - 如何通过 python click.version_option 装饰器的 Travis CI 测试?

python - 三角形/几何彩虹螺旋

mocking - Jest 快照失败 : val. getMockName 不是函数

unit-testing - 测试 BDD 中的副作用

database - 数据库相关应用程序的自动化单元测试

python - 使用 pytest 检查是否有任何测试引发弃用警告