【问题标题】:Python unit testing expected output from If StatementPython 单元测试来自 If 语句的预期输出
【发布时间】:2014-10-27 06:57:30
【问题描述】:

我目前正在创建一些单元测试。我对他们很陌生,只是想弄湿我的脚。所以我正在尝试运行的当前测试是根据用户输入检查预期的输出。所以我会用某种类型的值修补输入,然后检查最后是否收到了标准输出消息。听起来有点混乱,但我希望有人能提供帮助。这是我的运行代码。

def main():


  Attack = input("Are we being attacked?!")

  if(Attack == "yes"):
    print("We are being attacked! Attack Back!")

所以在上面的示例中,我将测试 print 语句,因为我将使用 yes 值修补用户输入。这是我的测试套件

import unittest
from unittest.mock import patch
import io
import sys

from RunFile import main

class GetInputTest(unittest.TestCase):

  @patch('builtins.input', return_value='yes')
  def test_output(self):
      saved_stdout = sys.stdout
      try:
          out = io.StringIO()
          sys.stdout = out
          main()
          output = out.getvalue().strip()
          self.assertEqual(output, "We are being attacked! Attack Back!")
      finally:
          sys.stdout = saved_stdout


if __name__ == "__main__":
  unittest.main()

所以这显然行不通。那么我错过了什么?提前谢谢大家!

已编辑:这是我在运行测试时收到的错误消息。我了解这个错误,只是不知道如何解决它。

Error
Traceback (most recent call last):
  File "C:\Python33\lib\unittest\mock.py", line 1087, in patched
    return func(*args, **keywargs)
TypeError: test_output() takes 1 positional argument but 2 were given

【问题讨论】:

  • 明显吗?相反会发生什么? "We are being attacked! Attack Back!""Hello Pirate!" 有什么关系?
  • 糟糕。我的错。完全忘记改变了。但无论如何它仍然不适合我。我编辑了我的代码。 @jonrsharpe
  • 您确定在您的测试中调用了正确的“main()”吗?会发生什么?它只是在断言上失败了?
  • 我编辑了我的代码以专门导入 main。我还包括了运行代码时收到的错误消息。我明白它告诉我什么,但不知道如何解决它。 @troylshields
  • 尝试在测试中添加一个参数,如下所示: def test_output(self, random): 看看它的作用。

标签: python unit-testing if-statement


【解决方案1】:

除了@chepner 的回答,您还需要使用unittest.TestCaseassert 方法而不是断言自己(双关语)

class TestStuff(unittest.TestCase):
    @patch('builtins.input', return_value='yes')
    def test_output(self, new_input):
        try:
            out = io.StringIO()
            sys.stdout = out
            main()
            output = out.getvalue().strip()
            self.assertEqual(output, "We are being attacked! Attack Back!")
        finally:
            sys.stdout = saved_stdout

但是,这可能不是完成您想做的事情的最佳方式。你可以修补多个内置函数,你知道的!

class TestStuff(unittest.TestCase):
    @patch('builtins.input', return_value='yes')
    @patch('builtins.print')
    def test_output(self, new_print, new_input):
        # the mocked functions are passed in opposite order
        # to where they're decorated
        main()
        new_print.assert_called_with("We are being attacked! Attack Back!")

如果装饰器很吓人,你甚至可以这样做:

class TestStuff(unittest.TestCase):
    def test_output(self):
        with patch('builtins.input', return_value='yes'), \
             patch('builtins.print') as new_print:
            main()
            new_print.assert_called_with("We are being attacked! Attack Back!")

【讨论】:

    【解决方案2】:

    patch 修饰的函数将Mock 作为附加参数。你需要

    @patch('builtins.input', return_value='yes')
    def test_output(self, m):
    

    第二个参数m 将是对Mock 对象的引用,当test_output 被调用时,该对象将替换input

    来自pydoc unittest.mockpatch

    如果patch 被用作装饰器并且new 被 省略,创建的模拟作为额外参数传入 装饰函数。

    【讨论】:

    • 好的,我试过了,它有点工作......它给了我“好的”,但它通过了测试,不管我的标准输出如何,所以基本上是预期的标准输出 =!实际的标准输出,仍然通过。
    • 它似乎对我有用。如果我更改模拟的返回值以更改 main 所做的事情,或者更改字符串 main 打印,则测试失败。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-07
    相关资源
    最近更新 更多