【问题标题】:Python 3 unittest simulate user inputPython 3 unittest 模拟用户输入
【发布时间】:2010-11-22 16:26:25
【问题描述】:

如何在单元测试调用的函数中间模拟用户输入(使用 Python 3 的单元测试)?例如,我有一个函数 foo() 我正在测试他的输出。在foo() 函数中,它要求用户输入:

x = input(msg)

并且输出是基于输入的:

print("input: {0}".format(x))

我希望我的单元测试运行foo(),输入一个输入并将结果与​​预期结果进行比较。

【问题讨论】:

    标签: unit-testing python-3.x


    【解决方案1】:

    当我尝试测试为用户输入带来对话框的代码时,我经常遇到这个问题,并且相同的解决方案应该适用于两者。您需要在您的测试范围内提供一个绑定到名称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_atest_input_b 保留为接受单个message 参数的函数,其中retval 参数已绑定。

    【讨论】:

    • 我最终做了类似的事情。我创建了一个 test_input 函数“test_input(msg)”,它将覆盖输入在我正在测试的模块上的默认行为:“module.input = test_input”。我正在使用在 test_input 函数之前定义并在每个测试用例之前设置的全局变量“sample_input”设置模拟输入值。
    • 您能否举例说明如何使用问题中提供的函数foo 进行注入?我不知道如何正确设置它。
    【解决方案2】:

    由于依赖关系而在测试某些组件时遇到困难,这通常是设计不佳的标志。您的 foo 函数不应依赖于全局 input 函数,而应依赖于参数。然后,当您在生产环境中运行程序时,您以这样一种方式连接事物,即调用 foo 并使用 input 返回的结果。所以foo 应该是:

    def foo(input):
        # do something with input
    

    这将使测试更加容易。顺便说一句,如果你的测试有IO 依赖,它们就不再是单元测试,而是功能测试。请查看Misko Hevery's blog,了解有关测试的更多见解。

    【讨论】:

    • 也许,但是在某处,有人正在收集该输入。当您想要测试这样做的方法时,您将不得不求助于操作 UI 以在该级别进行测试的功能测试工具,或者进行一些注入。当然,您还应该进行操作 UI 的功能测试,但这应该仅用于测试 UI(例如 input() 接受您提供的输入),而不是让故障渗入非 UI 实现细节的领域.
    • Nick,如果被测系统是遗留应用程序,其中重构非常困难或需要一些时间,但您确实希望进行一些特性测试(这实际上将支持重构),那么是的,我会使用你的方法。但是,如果应用程序正在开发中,则应该对其进行重构,以便于编写单元测试。
    • @Nick Bastin:“也许,但在某个地方,有人正在收集该输入。当您想测试这样做的方法时……”foo(input) 就是这样做的。没有“其他地方”需要对此进行测试。
    • @S.Lott:我不确定您为什么认为调用标准库输入调用的代码不需要测试。是的,在这个 super trivial 案例中,该代码可能只是调用 input 并调用您的 foo(input) 方法,但许多用户交互实例并不是那么简单。 (而且您显然仍然需要通过某种操作 UI 的方式来测试该代码)。
    【解决方案3】:

    我认为最好的方法是将input 函数包装在自定义函数上并模拟后者。就像这里描述的那样:python mocking raw input in unittests

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多