测试脚本输出

时间:2017-01-23 00:16:56

标签: python testing

我有一个Python脚本,它接受一个输入(文本文件):./myprog.py file.txt。脚本根据给定的输入输出一个字符串。

我有一组测试文件,我想测试我的程序。我知道每个文件的预期输出,并希望确保我的脚本为每个文件生成正确的输出。

进行此类测试的普遍接受方式是什么?

我在考虑使用Python的unittest模块作为测试框架,然后通过subprocess.check_output(stderr=subprocess.STDOUT)运行我的脚本,捕获stdoutstderr,然后执行{ {1}} unittest来比较实际和预期的字符串。我想确保我没有错过一些更好的解决方案。

1 个答案:

答案 0 :(得分:2)

这里有两个问题。测试程序,而不是函数库,测试打印的东西,而不是从函数返回的值。两者都使测试更加困难,因此最好尽可能地解决这些问题。

通常的技术是创建一个函数库,然后让你的程序成为一个薄的包装器。这些函数返回结果,只有程序才能进行打印。这意味着您可以对大多数代码使用常规单元测试技术。

您可以拥有一个既是库又是程序的文件。这是hello.py的一个简单示例。

def hello(greeting, place):
    return greeting + ", " + place + "!"

def main():
    print(hello("Hello", "World"))

if __name__ == '__main__':
    main()

最后一点是文件如何判断它是作为程序运行还是作为库导入。它允许使用import hello访问各个函数,并且还允许文件作为程序运行。 See this answer for more information

然后你可以编写一个大多数正常的单元测试。

import hello
import unittest
import sys
from StringIO import StringIO
import subprocess

class TestHello(unittest.TestCase):
    def test_hello(self):
        self.assertEqual(
             hello.hello("foo", "bar"),
            "foo, bar!"
        )

    def test_main(self):
        saved_stdout = sys.stdout
        try:
            out = StringIO()
            sys.stdout = out
            hello.main()
            output = out.getvalue()
            self.assertEqual(output, "Hello, World!\n")
        finally:
            sys.stdout = saved_stdout

    def test_as_program(self):
        self.assertEqual(
            subprocess.check_output(["python", "hello.py"]),
            "Hello, World!\n"
        )

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

此处test_hello直接将hello单元测试作为函数;在一个更复杂的程序中,会有更多的功能需要测试。我们还test_main使用StringIO对单元测试main进行单元测试以捕获其输出。最后,我们确保程序将作为test_as_program的程序运行。

重要的是测试与返回数据的函数一样多的功能,并尽可能少地测试打印和格式化的字符串,并且通过运行程序本身几乎没有。当我们实际测试该程序时,我们需要做的就是检查它是否调用main