PyDev unittesting: jak przechwycić tekst zalogowany do logowania.Logger in " przechwycone wyjście"
Używam PyDev do rozwoju i testowania jednostkowego mojej aplikacji Pythona. Jeśli chodzi o testy jednostkowe, wszystko działa świetnie, ponieważ treść logowana jest do dowolnego logowania. Logger nie jest przechwytywany przez" przechwycone wyjście " PyDev.
Już przesyłam wszystko co zalogowane do standardowego wyjścia tak:
import sys
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))
Mimo to "przechwycone wyjście"nie wyświetla rzeczy zapisanych do rejestratorów.
Tutaj przykład 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")
Wyjście konsoli to:
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
Ale przechwycone Wyjście do testu to:
======================== CAPTURED OUTPUT =========================
AA
Czy ktoś wie jak przechwycić wszystko jest rejestrowane na logging.Logger
podczas wykonywania tego testu?
4 answers
Problem polega na tym, że unittest
runner zastępuje sys.stdout
/sys.stderr
przed rozpoczęciem testów, a StreamHandler
nadal pisze do oryginału sys.stdout
.
Jeśli przypisujesz' current ' sys.stdout
do obsługi, powinno to działać(patrz kod poniżej).
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")
Chociaż lepszym podejściem byłoby dodanie / usunięcie obsługi podczas testu:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-28 20:15:48
Zmęczyło mnie ręczne dodawanie wspaniałego kodu do wszystkich setUp
s, Więc podklasowałem unittest.TestCase
z jakimś __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)
Teraz twój przypadek testowy może po prostu dziedziczyć z LoggedTestCase
, tzn. class TestCase(LoggedTestCase)
zamiast class TestCase(unittest.TestCase)
i gotowe. Alternatywnie możesz dodać linię __metaclass__
i zdefiniować logger
W teście lub nieco zmodyfikowaną LogThisTestCase
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:50
Sugerowałbym użycie LogCapture i testowanie, że naprawdę rejestrujesz to, czego oczekujesz:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-06 14:58:09
Też natknąłem się na ten problem. Skończyło się na podklasowaniu StreamHandler i nadpisaniu atrybutu stream właściwością, która dostaje sys.stdout. W ten sposób handler użyje strumienia, który jest unittest.TestCase zamienił się na sys.stdout:
class CapturableHandler(logging.StreamHandler):
@property
def stream(self):
return sys.stdout
@stream.setter
def stream(self, value):
pass
Możesz następnie skonfigurować obsługę logowania przed uruchomieniem testów w ten sposób (spowoduje to dodanie niestandardowej obsługi do dziennika głównego):
def setup_capturable_logging():
if not logging.getLogger().handlers:
logging.getLogger().addHandler(CapturableHandler())
Jeśli, podobnie jak ja, masz swoje testy w oddzielnych modułach, możesz po prostu umieścić linię po import każdego modułu testów jednostkowych, który upewni się, że logowanie jest ustawione przed uruchomieniem testów:
import logutil
logutil.setup_capturable_logging()
To może nie jest najczystsze podejście, ale jest dość proste i działa dobrze dla mnie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-21 23:31:38