在单元测试中隐藏stderr输出

16 投票
4 回答
6816 浏览
提问于 2025-04-15 16:27

我正在为一些代码写单元测试,这些代码使用 sys.stderr.write 来报告输入错误。这本来是对的,但这样会干扰单元测试的输出。有没有办法告诉 Python 不要输出某些命令的错误信息,就像在命令行中用 2> /dev/null 一样?

4 个回答

5

还有一种方法(除了直接把错误信息输出到 sys.stderr)是把你的代码设计成可以把错误写入一个指定的文件,但默认情况下这个文件是 sys.stderr。这样在测试的时候,你可以使用一个叫 DevNull 的写入器。

如果你确实想重新指定 sys.stderr,可以使用 unittest 这个框架来帮你管理:

class DevNull(object):
    def write(self, data): 
        pass

class MyTestCase(unittest.TestCase):
    def setUp(self):
        self.old_stderr = sys.stderr
        sys.stderr = DevNull()

    def tearDown(self):
        sys.stderr = self.old_stderr

这样做的话,每次测试的时候都会把错误信息丢到一个无效的地方,但测试结束后又会把它恢复回来。

12

你可以创建一个虚假的文件对象,这个对象不会处理它的输出,然后把错误输出(stderr)设置为这个对象:

class NullWriter:
    def write(self, s):
        pass

sys.stderr = NullWriter()

如果你只想在特定的时间段内让错误输出安静下来,可以使用一个 with 语句,像这样:

class Quieter:
    def __enter__(self):
        self.old_stderr = sys.stderr
        sys.stderr = NullWriter()

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

with Quieter():
    # Do stuff; stderr will be suppressed, and it will be restored
    # when this block exits

这个方法需要 Python 2.6 或更高版本,或者在 Python 2.5 中使用 from __future__ import with_statement 也可以。

26

我建议你写一个上下文管理器:

import contextlib
import sys

@contextlib.contextmanager
def nostderr():
    savestderr = sys.stderr
    class Devnull(object):
        def write(self, _): pass
        def flush(self): pass
    sys.stderr = Devnull()
    try:
        yield
    finally:
        sys.stderr = savestderr

现在,把你想要隐藏错误信息的代码放在 with nostderr(): 里面,这样就可以实现你想要的局部、临时、可逆的错误信息隐藏效果。

撰写回答