python PyDev unittesting: लॉगिंग में लॉग किए गए पाठ को कैप्चर कैसे करें। "कैप्चर आउटपुट" में लॉगर




unit-testing logging (4)

मैं अपने पायथन आवेदन के विकास और इकाई परीक्षण के लिए पीईडीवी का उपयोग कर रहा हूं। यूनिट-परीक्षण के लिए, सब कुछ बड़ी ओर से काम करता है तथ्य यह है कि सामग्री किसी भी लॉगिंग के लिए लॉग इन है। लॉगर को पीडीडीव के "कैप्चर आउटपुट" द्वारा कैद नहीं किया जाता है।

मैं पहले से ही मानक आउटपुट में लॉग इन सब कुछ अग्रेषित करता हूं:

import sys
logger = logging.getLogger()
logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout))

फिर भी "कैप्चर आउटपुट" लॉगर्स को लॉग इन सामग्री प्रदर्शित नहीं करता है।

यहां एक उदाहरण 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")

कंसोल आउटपुट है:

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

लेकिन परीक्षण के लिए कैप्चर आउटपुट है:

======================== CAPTURED OUTPUT =========================
AA

क्या कोई जानता है कि logging.Logger सबकुछ कैप्चर करना है लॉग इन करें। इस परीक्षण के निष्पादन के दौरान logging.Logger ?


मैं एक लॉग कैप्चर और परीक्षण का उपयोग करने का सुझाव दूंगा कि आप वास्तव में लॉगिंग करने की अपेक्षा करते हुए लॉगिंग कर रहे हैं:

http://testfixtures.readthedocs.org/en/latest/logging.html


मैं भी इस समस्या में आया था। मैं StreamHandler subclassing समाप्त हो गया, और sys.stdout मिलता है कि एक संपत्ति के साथ धारा विशेषता ओवरराइडिंग। इस तरह, हैंडलर उस स्ट्रीम का उपयोग करेगा जो unittest.TestCase sys.stdout में बदल गया है:

class CapturableHandler(logging.StreamHandler):

    @property
    def stream(self):
        return sys.stdout

    @stream.setter
    def stream(self, value):
        pass

इसके बाद आप परीक्षण चलाने से पहले लॉगिंग हैंडलर सेट कर सकते हैं (यह रूट हैंगर को कस्टम हैंडलर जोड़ देगा):

def setup_capturable_logging():
    if not logging.getLogger().handlers:
        logging.getLogger().addHandler(CapturableHandler())

यदि, मेरे जैसे, आपके पास अलग-अलग मॉड्यूल में आपके परीक्षण हैं, तो आप प्रत्येक इकाई परीक्षण मॉड्यूल के आयात के बाद केवल एक लाइन डाल सकते हैं जो सुनिश्चित करेगा कि परीक्षण चलाने से पहले लॉगिंग सेटअप हो:

import logutil

logutil.setup_capturable_logging()

यह सबसे साफ दृष्टिकोण नहीं हो सकता है, लेकिन यह बहुत आसान है और मेरे लिए अच्छा काम करता है।


मुद्दा यह है कि परीक्षण शुरू होने से पहले unittest धावक sys.stdout / sys.stderr को प्रतिस्थापित sys.stdout , और StreamHandler अभी भी मूल sys.stdout लिख रहा है।

यदि आप हैंडलर को 'वर्तमान' sys.stdout असाइन करते हैं, तो इसे काम करना चाहिए (नीचे दिए गए कोड को देखें)।

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")

हालांकि, परीक्षण के दौरान हैंडलर को बेहतर तरीके से जोड़ना / निकालना होगा:

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)

मैं सभी setUp के लिए फैबियो के महान कोड को मैन्युअल रूप से जोड़ने के थक गया था, इसलिए मैंने कुछ __metaclass__ ing के साथ unittest.TestCase subclassed:

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)

अब आपका टेस्ट केस class TestCase(LoggedTestCase) class TestCase(unittest.TestCase) बजाय class TestCase(LoggedTestCase) LoggedTestCase , यानी class TestCase(LoggedTestCase) सकता है और आप कर चुके हैं। वैकल्पिक रूप से, आप __metaclass__ लाइन जोड़ सकते हैं और __metaclass__ में या तो थोड़ा संशोधित LogThisTestCase में logger को परिभाषित कर सकते हैं।





pydev