2009-11-27 8 views
14

Estoy escribiendo algunas pruebas unitarias de algún código que usa sys.stderr.write para informar errores en la entrada. Esto es como debería ser, pero esto anula la salida de prueba de la unidad. ¿Hay alguna manera de decirle a Python que no muestre mensajes de error para comandos individuales, a la 2> /dev/null?Ocultar resultados de stderr en pruebas unitarias

Respuesta

23

Sugiero escribir un gestor de contexto:

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 

Ahora, envuelva cualquier fragmento de código cuya stderr que desea suprimida en un with nostderr(): y usted tiene la localizada, reversible garantizada por supresión temporal, stderr que desea.

+1

¡Guau! Esto es maravilloso. No estaba al tanto de contextlib antes porque aún uso Python 2.4. –

+0

@shailesh, sí, contextlib facilita la escritura de la mayoría de los gestores de contexto simples (escribir una clase con '__enter__' y' __exit__' no es difícil por supuesto, pero de esta manera, para casos suficientemente simples, tiene incluso menos código repetitivo que escribir y leer;-). –

+0

¿Por qué no 'sys.stderr = os.devnull' – Matt3o12

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

sys.stderr = DevNull() 

tener una solución menos permanente, se podría averiguar algo así como de la siguiente manera:

_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 

Los nombres de función probablemente puede ser mejor

+0

Esperaba una solución menos permanente. ¿No hay forma de ajustar un comando como 'quiet (...)'? – l0b0

+1

No es necesario almacenar una copia de seguridad. Python ya tiene un sys .__ stderr__ http://docs.python.org/library/sys.html#sys.__stderr__ –

+1

El motivo para almacenar la copia de seguridad es para que nada sea absoluto: quién sabe si alguna otra entidad de código más grande cambió el sistema. .stderr antes de ser invocado? De esta manera, simplemente estás deshaciendo tu primera acción. –

12

Se puede crear un objeto de archivo ficticio que no hizo nada con su salida, y establecer stderr a eso:

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

sys.stderr = NullWriter() 

Si solo quieres calmar stde rr durante un tiempo determinado, puede utilizar una declaración with así:

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 

Requiere Python 2.6 o superior, o se puede utilizar en Python 2.5 con un from __future__ import with_statement.

4

Otra posibilidad (además de la asignación a sys.stderr) es estructurar el código para escribir errores en un archivo proporcionado, pero a ese archivo por defecto a sys.stderr. Luego puede proporcionar un escritor DevNull durante la prueba.

Si desea reasignar sys.stderr, puede utilizar el marco unittest para manejarlo para usted:

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 

De esta manera, todas las pruebas de stderr dev-nulo, pero luego lo restaura al final del examen.

+0

Esto también tiene la ventaja de que puede verificar el resultado en su prueba si así lo desea. –