我有一个用Python编写的控制台程序。它要求使用该命令的用户的问题:Pytest:如何通过输入调用来测试函数?
some_input = input('Answer the question:', ...)
我将如何测试中,含有使用pytest
到input
通话功能? 我不想强迫测试人员多次输入文本来完成一次测试运行。
我有一个用Python编写的控制台程序。它要求使用该命令的用户的问题:Pytest:如何通过输入调用来测试函数?
some_input = input('Answer the question:', ...)
我将如何测试中,含有使用pytest
到input
通话功能? 我不想强迫测试人员多次输入文本来完成一次测试运行。
您应该嘲笑内置的input
函数,您可以使用pytest
提供的teardown
功能在每次测试后恢复原始的input
函数。
import module # The module which contains the call to input
class TestClass:
def test_function_1(self):
# Override the Python built-in input method
module.input = lambda: 'some_input'
# Call the function you would like to test (which uses input)
output = module.function()
assert output == 'expected_output'
def test_function_2(self):
module.input = lambda: 'some_other_input'
output = module.function()
assert output == 'another_expected_output'
def teardown_method(self, method):
# This method is being called after each test case, and it will revert input back to original function
module.input = input
更好的解决方案将是为与with statement
一起使用mock
模块。这样你就不需要使用拆卸,修补后的方法只能在with
范围内生存。
import mock
import module
def test_function():
with mock.patch.object(__builtin__, 'input', lambda: 'some_input'):
assert module.function() == 'expected_output'
正如编译器建议的,pytest有一个新的monkeypatch夹具。对象可以更改类中的属性或字典中的值,然后在测试结束时恢复其原始值。
在这种情况下,内置的input
功能是Python __builtins__
字典的价值,所以我们可以改变它,如下所示:
def test_something_that_involves_user_input(monkeypatch):
# monkeypatch the "input" function, so that it returns "Mark".
# This simulates the user entering "Mark" in the terminal:
monkeypatch.setitem('builtins.input', lambda x: "Mark")
# go about using input() like you normally would:
i = input("What is your name?")
assert i == "Mark"
编辑:改变lambda: "Mark"
到lambda x: "Mark"
这应该是'setattr',而不是'setitem'。 – Matt
您可以更换sys.stdin
与一些自定义Text IO,如来自文件或内存中的StringIO缓冲区的输入:
import sys
class Test:
def test_function(self):
sys.stdin = open("preprogrammed_inputs.txt")
module.call_function()
def setup_method(self):
self.orig_stdin = sys.stdin
def teardown_method(self):
sys.stdin = self.orig_stdin
这比只修补input()
更稳健,因为如果模块使用任何其他从标准输入消耗文本的方法,这将不够。
这也可以很优雅地完成了一个自定义的上下文管理
import sys
from contextlib import contextmanager
@contextmanager
def replace_stdin(target):
orig = sys.stdin
sys.stdin = target
yield
sys.stdin = orig
,然后只用像这样的例子:
with replace_stdin(StringIO("some preprogrammed input")):
module.call_function()
可以按如下方式与mock.patch
做到这一点。
首先,在你的代码,创建调用虚拟函数input
:
def __get_input(text):
return input(text)
在您的测试功能:
import my_module
from mock import patch
@patch('my_module.__get_input', return_value='y'))
def test_what_happens_when_answering_yes(self, mock):
"""
Test what happens when user input is 'y'
"""
# whatever your test function does
例如,如果你已经一个循环检查的只有有效答案是['y','Y','n','N'],您可以测试在输入不同的值时没有任何反应。
在这种情况下,我们假设一个
SystemExit
引发回答“N”时:
@patch('my_module.__get_input')
def test_invalid_answer_remains_in_loop(self, mock):
"""
Test nothing's broken when answer is not ['Y', 'y', 'N', 'n']
"""
with self.assertRaises(SystemExit):
mock.side_effect = ['k', 'l', 'yeah', 'N']
# call to our function asking for input
你去翻关于如何使用'pytest'看你可以尝试什么教程?这是一个相当宽泛的问题。 – idjaw
@idjaw不是最近。我之前使用过pytest,但是当考虑在我的项目中为TDD做TDD时,我想到了这一点,但我不知道如何解决它。我会再看看那些馅饼。 – Zelphir
在您的测试函数中,您可以将'input()'函数重新分配给别的东西(也称为“猴子修补”或“阴影”)。 –