python - tests - Prueba unitaria PyDev: Cómo capturar texto registrado en un registro. Iniciador en "Salida capturada"
unit test en python (4)
El problema es que el sys.stdout
unittest
reemplaza sys.stdout
/ sys.stderr
antes de que sys.stderr
la prueba, y StreamHandler
todavía está escribiendo en el sys.stdout
original.
Si asigna el ''actual'' sys.stdout
al controlador, debería funcionar (vea el código a continuación).
import sys
import unittest
import logging
logger = logging.getLogger()
logger.level = logging.DEBUG
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
class TestCase(unittest.TestCase):
def testSimpleMsg(self):
stream_handler.stream = sys.stdout
print("AA")
logging.getLogger().info("BB")
Sin embargo, un mejor enfoque sería agregar / eliminar el controlador durante la prueba:
import sys
import unittest
import logging
logger = logging.getLogger()
logger.level = logging.DEBUG
class TestCase(unittest.TestCase):
def testSimpleMsg(self):
stream_handler = logging.StreamHandler(sys.stdout)
logger.addHandler(stream_handler)
try:
print("AA")
logging.getLogger().info("BB")
finally:
logger.removeHandler(stream_handler)
Estoy usando PyDev para desarrollo y pruebas unitarias de mi aplicación Python. En cuanto a las pruebas unitarias, todo funciona en gran medida por el hecho de que el contenido se haya registrado en cualquier registro. Logger no es capturado por la "Salida capturada" de PyDev.
Ya reenvío todo lo registrado a la salida estándar de esta manera:
import sys
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
Sin embargo, la "Salida capturada" no muestra las cosas registradas en los registradores.
Aquí un ejemplo unittest-script: test.py
import sys
import unittest
import logging
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
class TestCase(unittest.TestCase):
def testSimpleMsg(self):
print("AA")
logging.getLogger().info("BB")
La salida de la consola es:
Finding files... done.
Importing test modules ... done.
testSimpleMsg (itf.lowlevel.tests.hl7.TestCase) ... AA
2011-09-19 16:48:00,755 - root - INFO - BB
BB
ok
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Pero la SALIDA CAPTURADA para la prueba es:
======================== CAPTURED OUTPUT =========================
AA
¿Alguien sabe cómo capturar todo lo que se registra en un logging.Logger
durante la ejecución de esta prueba?
Me cansé de tener que agregar manualmente el gran código de Fabio a todos los setUp
, así que __metaclass__
unittest.TestCase
con algunos __metaclass__
ing:
class LoggedTestCase(unittest.TestCase):
__metaclass__ = LogThisTestCase
logger = logging.getLogger("unittestLogger")
logger.setLevel(logging.DEBUG) # or whatever you prefer
class LogThisTestCase(type):
def __new__(cls, name, bases, dct):
# if the TestCase already provides setUp, wrap it
if ''setUp'' in dct:
setUp = dct[''setUp'']
else:
setUp = lambda self: None
print "creating setUp..."
def wrappedSetUp(self):
# for hdlr in self.logger.handlers:
# self.logger.removeHandler(hdlr)
self.hdlr = logging.StreamHandler(sys.stdout)
self.logger.addHandler(self.hdlr)
setUp(self)
dct[''setUp''] = wrappedSetUp
# same for tearDown
if ''tearDown'' in dct:
tearDown = dct[''tearDown'']
else:
tearDown = lambda self: None
def wrappedTearDown(self):
tearDown(self)
self.logger.removeHandler(self.hdlr)
dct[''tearDown''] = wrappedTearDown
# return the class instance with the replaced setUp/tearDown
return type.__new__(cls, name, bases, dct)
Ahora su caso de prueba simplemente puede heredar de LoggedTestCase
, es decir, la class TestCase(LoggedTestCase)
lugar de la class TestCase(unittest.TestCase)
y listo. Alternativamente, puede agregar la línea __metaclass__
y definir el logger
en la prueba o LogThisTestCase
ligeramente modificado.
Me encontré con este problema también. Terminé subclasando StreamHandler y anulando el atributo de flujo con una propiedad que obtiene sys.stdout. De esta forma, el controlador utilizará la secuencia que prueba la unidad. TestCase se ha cambiado a sys.stdout:
class CapturableHandler(logging.StreamHandler):
@property
def stream(self):
return sys.stdout
@stream.setter
def stream(self, value):
pass
A continuación, puede configurar el controlador de registro antes de ejecutar pruebas de ese modo (esto agregará el controlador personalizado al registrador de raíz):
def setup_capturable_logging():
if not logging.getLogger().handlers:
logging.getLogger().addHandler(CapturableHandler())
Si, como yo, tiene sus pruebas en módulos separados, puede simplemente poner una línea después de las importaciones de cada módulo de prueba de la unidad que se asegurará de que el registro esté configurado antes de ejecutar las pruebas:
import logutil
logutil.setup_capturable_logging()
Este podría no ser el enfoque más limpio, pero es bastante simple y funcionó bien para mí.
Sugeriría usar un LogCapture y probar que realmente estás registrando lo que esperas que esté registrando: