Скрыть вывод stderr в модульных тестах

Я пишу несколько модульных тестов некоторого кода, который использует sys.stderr.write для сообщения об ошибках ввода. Это как и должно быть, но это сжимает вывод unit test. Есть ли способ сказать Python не выводить сообщения об ошибках для одиночных команд, à la 2> /dev/null?

Ответы

Ответ 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 которого вы хотите подавить в with nostderr():, и у вас есть локализованное, временное, гарантированное обратимое подавление stderr, которое вы хотите.

Ответ 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

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

Названия функций могут быть лучше

Ответ 4

Другая возможность (помимо назначения sys.stderr) состоит в том, чтобы структурировать ваш код для записи ошибок в предоставленный файл, но по умолчанию этот файл для sys.stderr. Затем вы можете предоставить писатель DevNull во время тестирования.

Если вы хотите переназначить sys.stderr, вы можете использовать Unittest framework для управления им для вас:

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 stderr, но затем восстанавливает его в конце теста.