丢弃被测程序的stdout / stderr,但保持unittest输出

时间:2015-06-08 17:18:17

标签: python stdout stderr python-unittest

我有这个示例代码(test_it.py):

import sys

def give_me_5():
    print >>sys.stdout, "STDOUT"
    print >>sys.stderr, "STDERR"
    return 6

import unittest


class TestMe(unittest.TestCase):

    def setUp(self):
        pass

    def test_give_me_5(self):
        self.assertEqual(give_me_5(), 5)


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

这给了我以下输出:

» python -m unittest test_it
A long annoying output message
A long annoying error message
F
======================================================================
FAIL: test_give_me_5 (__main__.TestMe)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xx.py", line 17, in test_give_me_5
    self.assertEqual(give_me_5(), 5)
AssertionError: 6 != 5

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

但是由于被测程序产生的冗长,恼人的消息(真正的程序产生很多输出),我无法看到unittest的输出。我想摆脱正在测试的函数(give_me_5)的stdout / stderr,但我仍然希望看到unittest的stdout / stderr。我想得到这个结果:

» python -m unittest test_it
F
======================================================================
FAIL: test_give_me_5 (__main__.TestMe)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xx.py", line 17, in test_give_me_5
    self.assertEqual(give_me_5(), 5)
AssertionError: 6 != 5

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (failures=1)

因此,被测程序(stdout和stderr)产生的输出被unittest过滤掉,但是unittest本身产生的输出保持。我不想修改被测试的代码(代码本身没有重定向)。我只想告诉unittest所有被测试代码生成的stdout / stderr输出都应该被丢弃。

这可能吗?

3 个答案:

答案 0 :(得分:5)

@Alik建议是对的。但我想它可以改进。

import sys
# StringIO is replaced in Python 3:
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

class ReplaceStd(object):
    """ Let's make it pythonic. """

    def __init__(self):
        self.stdout = None
        self.stderr = None

    def __enter__(self):
        self.stdout = sys.stdout
        self.stderr = sys.stderr

        # as it was suggseted already:
        sys.stdout = StringIO()
        sys.stderr = StringIO()

    def __exit__(self, type, value, traceback):
        sys.stdout = self.stdout
        sys.stderr = self.stderr

print('I am here')
with ReplaceStd():
    print('I am not')

print('I am back')

输出:

I am here
I am back

答案 1 :(得分:4)

暂时将body.home #header { z-index: 10; } sys.stdout替换为类似文件的实例。例如,您可以使用StringIO也称为内存缓冲区。

sys.stderr

您可能希望添加异常处理,甚至可以在上下文管理器中将此代码转换为重用

答案 2 :(得分:0)

供参考(以及获取评论),这是我最终使用的代码(受到@Alik的回复启发):

import sys

def give_me_5():
    print >>sys.stdout, "A long annoying output message"
    print >>sys.stderr, "A long annoying error message"
    return 6


import unittest

def redirect(stdout_file=None, stderr_file=None):
    new_stdout = open(stdout_file, 'w') if stdout_file else None
    new_stderr = open(stderr_file, 'w') if stderr_file else None
    if new_stdout : sys.stdout = new_stdout
    if new_stderr : sys.stderr = new_stderr

def redirect_testcase(test_case):
    logfile = '.'.join([test_case.__module__, test_case.__class__.__name__, 'out'])
    errfile = '.'.join([test_case.__module__, test_case.__class__.__name__, 'err'])
    redirect(logfile, errfile)


class TestMe(unittest.TestCase):

    def setUp(self):
        redirect_testcase(self)

    def test_give_me_5(self):
        self.assertEqual(give_me_5(), 5)

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

现在只需执行redirect_testcase(self),stdout / stderr就会重定向到test_it.TestMe.out / test_it.TestMe.err,并且unittest的输出在控制台stdout / stderr中可见(并且可以重定向)如果需要可以通过shell。

存在一个问题(我还不知道如何修复):特定TestCase中的所有测试都将覆盖.out / .err个文件。最好为每个测试打开一个不同的out / log文件(而不是每个TestCase的常用文件)