[英]Testing Python functions that require user input()
I want to test the following function:我想测试以下功能:
def get_inputs():
str_from_user = input()
list_of_marks = []
while str_from_user != "exit":
list_of_marks.append('!')
str_from_user = input()
return list_of_marks
is there a way to test multiple scenarios?有没有办法测试多个场景? something like this (but only that works):像这样的东西(但只有这样有效):
def test_get_inputs():
assert get_inputs(){"hey", "coco", "milo", "exit"} == "!!!"
assert get_inputs(){"exit"} == ""
assert get_inputs(){"horses have long faces", "exit} == "!"
There is no obvious way to test your function as it is currently written, because you are reading from standard input.没有明显的方法来测试当前编写的函数,因为您是从标准输入读取的。 This is a side effect that makes your function non- pure and hard to test.这是一个副作用,使您的函数不纯且难以测试。 In other words, the input comes from outside your program, so you do not have control over it.换句话说,输入来自您的程序外部,因此您无法控制它。
You should rewrite your function in a way that makes it easy to provide input and check output within the program.您应该以一种易于在程序中提供输入和检查输出的方式重写您的函数。 You can do this passing a function to use as a way to get input instead of always using input()
.您可以通过传递一个函数来执行此操作,以用作获取输入的一种方式,而不是始终使用input()
。 Then, for testing, you can create a simple iterator object over a list of known inputs and pass its __next__
method as input function.然后,为了测试,您可以在已知输入列表上创建一个简单的迭代器对象,并将其__next__
方法作为输入函数传递。
Here's an example of how this could be done:这是一个如何做到这一点的示例:
def get_inputs(input_function):
str_from_user = input_function()
list_of_marks = []
while str_from_user != "exit":
list_of_marks.append('!')
str_from_user = input_function()
return list_of_marks
def test_get_inputs():
input_func_one = iter(["hey", "coco", "milo", "exit"]).__next__
input_func_two = iter(["exit"]).__next__
input_func_three = iter(["horses have long faces", "exit"]).__next__
assert get_inputs(input_func_one) == ['!', '!', '!']
assert get_inputs(input_func_two) == []
assert get_inputs(input_func_three) == ['!']
Another option, as suggested by @chepner in the above comments, would be to pass the function a file-like object, which can be easily mocked using the io
module with either BytesIO
or StringIO
.正如@chepner在上述评论中所建议的那样,另一个选项是向函数传递一个类似文件的对象,可以使用带有BytesIO
或StringIO
的io
模块轻松模拟该对象。 Take care in this case though because input()
strips the trailing newline, but StringIO.readline()
does not.在这种情况下要小心,因为input()
会去除尾随的换行符,但StringIO.readline()
不会。
from io import StringIO
def get_inputs(input_file):
str_from_user = input_file.readline().rstrip()
list_of_marks = []
while str_from_user != "exit":
list_of_marks.append('!')
str_from_user = input_file.readline().rstrip()
return list_of_marks
def test_get_inputs():
assert get_inputs(StringIO("hey\ncoco\nmilo\nexit\n")) == ['!', '!', '!']
assert get_inputs(StringIO("exit\n")) == []
assert get_inputs(StringIO("horses have long faces\nexit\n")) == ['!']
You could also adapt the first case (passing an input function) to work with StringIO
by simply passing StringIO("...").readline
as function.您还可以通过简单地将StringIO("...").readline
作为函数传递来调整第一种情况(传递输入函数)以使用StringIO
。
Not what you have a function that is easily testable, you can write a simple wrapper that uses the function and works with standard input instead:不是你有一个易于测试的函数,你可以编写一个使用该函数并使用标准输入的简单包装器:
# If using an input function
def get_inputs_from_stdin():
return get_inputs(input)
# If using a file-like object
import sys
def get_inputs_from_stdin():
return get_inputs(sys.stdin)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.