对打印到标准输出的程序执行单元测试的好策略?

2024-05-07 22:04:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个大约500行的python程序,可以写入stdout(使用print语句)。现在我想做一些改变并重构程序,但我想确保在这样做的过程中,我能得到相同的输出(当然,给定相同的输入)。在

在不重写函数以返回字符串(允许更容易的测试)而不是当前的print-ing的情况下,这样做的好策略是什么?在

我想把最初的输出(在我开始改变它之前)重定向到一个文本文件。我怎样才能轻松地自动地用文本文件检查修改过的程序的输出(而不必再次将输出重定向到临时文本文件并比较这些文件)?在

编辑:这是我决定的解决方案:

def test_something():
    # using lambda because we might test function with parameters
    f = lambda: thing_to_test
    test_generic('expect_output.txt', f)

def test_generic(filename_expected, function_to_test):

    #Run and write to tmp file
    tmpfile = 'test-tmp.txt'
    sys.stdout = open(tmpfile, 'w')
    function_to_test()
    sys.stdout = sys.__stdout__

    #compare with expected output
    expected = open(filename_expected).read()
    result = open(tmpfile).read()
    d = difflib.Differ()
    diff = d.compare(expected.splitlines(), result.splitlines())

    #print result (different lines only)
    diff_lines_only = [line for line in diff if line[0] in "+-?"]
    if not diff_lines_only:
        print "Test succeeded (%s)\n" % filename_expected
        os.remove(tmpfile)
    else:
        print "Test FAILED (%s):\n" % filename_expected
        print '\n'.join(list(diff_lines)) 

编辑2:实际上,我认为我在下面作为答案提供的doctest解决方案要好得多。在


Tags: totest程序stdoutsysdifffunctionresult
3条回答

有趣的小例子问题-我用它来创建一个print/capture/diffcompare solution using pytest。请注意,这个例子高级地使用了pytest特性,但是这些特性是链接的,并有完整的文档记录,在许多其他情况下也很有用。实际上,这个解决方案需要不到当前顶级解决方案一半的代码,而且您可能会发现能够有选择地运行测试或其他一些other pytest features的代码是很不错的。在

假设您正在运行Bash,那么可以运行diff -u orig-file <(python my-program.py)。这将在原始文件(您已经将原始输出写入其中)和程序将写入的命名管道之间进行区分。在

下面是一个简单的示例,使用echo而不是实际的Python脚本:

$ diff -u <(echo $'foo\nbar\nbaz') <(echo $'foo\nbar\nquux')
--- /dev/fd/63  2012-11-08 15:07:09.000000000 -0500
+++ /dev/fd/62  2012-11-08 15:07:09.000000000 -0500
@@ -1,3 +1,3 @@
 foo
 bar
-baz
+quux

您可以获得表示程序重定向sys.stdout输出的字符串。 要比较输出,可以使用^{}模块。尤其是Differ类与diff命令的作用差不多:

>>> import difflib
>>> text = '''bar
... baz
... '''
>>> text2 = '''foo
... bar
... '''
>>> d = difflib.Differ()
>>> for line in d.compare(text.splitlines(), text2.splitlines()):
...     print line
... 
+ foo
  bar
- baz

如果我没搞错的话,unittest2的assertEqual已经尝试显示字符串的差异,但是我不知道在哪个级别,输出是否足够简单。在

相关问题 更多 >