【问题标题】:Hide stderr output in unit tests在单元测试中隐藏标准错误输出
【发布时间】:2009-11-27 17:47:10
【问题描述】:

我正在编写一些代码的单元测试,这些代码使用 sys.stderr.write 来报告输入错误。这是应该的,但这会破坏单元测试输出。有什么方法可以告诉 Python 不为单个命令输出错误消息,比如 2> /dev/null

【问题讨论】:

    标签: python unit-testing


    【解决方案1】:

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

    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
    

    现在,将您想要抑制其 stderr 的任何代码 sn-p 包装在 with nostderr(): 中,并且您拥有所需的本地化、临时、保证可逆的 stderr 抑制。

    【讨论】:

    • 哇!这太棒了。在因为我仍然使用 Python 2.4 之前不知道 contextlib。
    • @shailesh,是的,contextlib 有助于编写大多数简单的上下文管理器(用__enter____exit__ 编写一个类当然不难,但是这样,对于足够简单的情况,您可以编写和阅读的样板代码更少;-)。
    • 为什么不sys.stderr = os.devnull
    • @Matt3o12:因为 os.devnull 只是一个字符串(例如 Linux 系统上的“/dev/null”),而不是文件描述符。
    【解决方案2】:

    您可以创建一个不对其输出执行任何操作的虚拟文件对象,并将 stderr 设置为:

    class NullWriter:
        def write(self, s):
            pass
    
    sys.stderr = NullWriter()
    

    如果您只想让 stderr 安静一段时间,您可以使用 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

    【讨论】:

      【解决方案3】:

      另一种可能性(除了分配给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
      

      这样,每个测试 dev-null 的标准错误,然后在测试结束时恢复它。

      【讨论】:

      • 这还有一个好处是你可以在你的测试中检查输出,如果你愿意的话。
      【解决方案4】:
      class DevNull(object):
          def write(self, data): pass
      
      sys.stderr = DevNull()
      

      要找到一个不太持久的解决方案,可以想出如下方法:

      _stderr = None
      def quiet():
          global _stderr
          if _stderr is None:
              _stderr = sys.stderr
              sys.stderr = DevNull()
      
      def verbose():
         global _stderr
         if _stderr is not None:
             sys.stderr = _stderr
            _stderr = None
      

      函数名可能会更好

      【讨论】:

      • 我希望有一个不那么持久的解决方案。有没有办法包装像quiet(...)这样的命令?
      • 无需存储备份。 Python 已经有一个 sys.__stderr__ docs.python.org/library/sys.html#sys.__stderr__
      • 存储备份的原因是没有什么是绝对的:谁知道其他更大的代码实体在您被调用之前是否更改了 sys.stderr?这样,您只需撤消您的第一个操作。
      猜你喜欢
      • 1970-01-01
      • 2014-08-05
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      • 1970-01-01
      • 2015-11-30
      • 1970-01-01
      相关资源
      最近更新 更多