Скрыть вывод stderr в модульных тестах - PullRequest
15 голосов
/ 27 ноября 2009

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

Ответы [ 4 ]

24 голосов
/ 27 ноября 2009

Я предлагаю написать контекстный менеджер:

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, которое вы хотите.

12 голосов
/ 27 ноября 2009

Вы можете создать фиктивный файловый объект, который ничего не делал с его выводом, и установить для него 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.

5 голосов
/ 27 ноября 2009

Другая возможность (помимо присвоения 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

Таким образом, каждый тестовый stderr dev-null, но затем восстанавливает его в конце теста.

4 голосов
/ 27 ноября 2009
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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...