如何使用pytestmonkeypatch模拟两个连续的控制台输入 [英] How to simulate two consecutive console inputs with pytest monkeypatch
问题描述
如果第一个用户输入的回答是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屋!