Python单元测试中If语句的预期输出

1 投票
2 回答
2357 浏览
提问于 2025-04-19 11:34

我现在正在创建一些单元测试。我对这个还比较陌生,只是在尝试入门。所以我现在要运行的测试是根据用户输入检查预期的输出。我会用某种值来替代输入,然后检查最后是否收到了标准输出的信息。听起来有点复杂,但我希望有人能帮忙。以下是我的运行代码。

def main():


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

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

在上面的例子中,我会测试打印语句,因为我会把用户输入替换成“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

2 个回答

2

除了@chepner的回答,你还需要使用unittest.TestCase里的assert方法,而不是自己去判断(这句话有点双关意思哦)

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,那么创建的mock会作为额外的参数传递给被装饰的函数。

撰写回答