【发布时间】:2010-11-22 16:26:25
【问题描述】:
如何在单元测试调用的函数中间模拟用户输入(使用 Python 3 的单元测试)?例如,我有一个函数 foo() 我正在测试他的输出。在foo() 函数中,它要求用户输入:
x = input(msg)
并且输出是基于输入的:
print("input: {0}".format(x))
我希望我的单元测试运行foo(),输入一个输入并将结果与预期结果进行比较。
【问题讨论】:
如何在单元测试调用的函数中间模拟用户输入(使用 Python 3 的单元测试)?例如,我有一个函数 foo() 我正在测试他的输出。在foo() 函数中,它要求用户输入:
x = input(msg)
并且输出是基于输入的:
print("input: {0}".format(x))
我希望我的单元测试运行foo(),输入一个输入并将结果与预期结果进行比较。
【问题讨论】:
当我尝试测试为用户输入带来对话框的代码时,我经常遇到这个问题,并且相同的解决方案应该适用于两者。您需要在您的测试范围内提供一个绑定到名称input 的新函数,其签名与标准input 函数相同,该函数仅返回一个测试值而不会实际提示用户。根据您的测试和代码的设置方式,这种注入可以通过多种方式完成,因此我将把它作为练习留给读者,但您的替换方法将很简单,例如:
def my_test_input(message):
return 7
显然,如果相关,您也可以打开message 的内容,并返回您选择的数据类型。您还可以做一些更灵活和通用的事情,允许在多种情况下重用相同的替换方法:
def my_test_input(retval, message):
return retval
然后你将一个部分函数注入input:
import functools
test_input_a = functools.partial(my_test_input, retval=7)
test_input_b = functools.partial(my_test_input, retval="Foo")
将test_input_a 和test_input_b 保留为接受单个message 参数的函数,其中retval 参数已绑定。
【讨论】:
foo 进行注入?我不知道如何正确设置它。
由于依赖关系而在测试某些组件时遇到困难,这通常是设计不佳的标志。您的 foo 函数不应依赖于全局 input 函数,而应依赖于参数。然后,当您在生产环境中运行程序时,您以这样一种方式连接事物,即调用 foo 并使用 input 返回的结果。所以foo 应该是:
def foo(input):
# do something with input
这将使测试更加容易。顺便说一句,如果你的测试有IO 依赖,它们就不再是单元测试,而是功能测试。请查看Misko Hevery's blog,了解有关测试的更多见解。
【讨论】:
foo(input) 就是这样做的。没有“其他地方”需要对此进行测试。
我认为最好的方法是将input 函数包装在自定义函数上并模拟后者。就像这里描述的那样:python mocking raw input in unittests
【讨论】: