89 Stimmen

PyDev Unittesting: Wie man Text, der in einem logging.Logger protokolliert wird, in "Captured Output" erfasst

Ich verwende PyDev für die Entwicklung und das Unit-Testing meiner Python-Anwendung. Was das Unit-Testing betrifft, so funktioniert alles prima, außer der Tatsache, dass kein Inhalt im Logging-Framework protokolliert wird. Der Logger wird nicht von der "Captured output" von PyDev erfasst.

Ich leite bereits alles, was protokolliert wird, auf diese Weise an die Standardausgabe weiter:

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

Dennoch zeigt die "Erfasste Ausgabe" nicht an, was in den Loggern protokolliert wird.

Hier ist ein Beispiel für ein Unittest-Skript: 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")

Die Konsolenausgabe lautet:

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

Aber die ERFASSTE LEISTUNG für den Test ist:

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

Weiß jemand, wie man alles erfassen kann, was in einer logging.Logger während der Durchführung dieses Tests?

2voto

Narotak Punkte 41

Ich bin auch auf dieses Problem gestoßen. Am Ende habe ich StreamHandler unterklassifiziert und das Stream-Attribut mit einer Eigenschaft überschrieben, die sys.stdout erhält. Auf diese Weise wird der Handler den Stream verwenden, den unittest.TestCase in sys.stdout ausgelagert hat:

class CapturableHandler(logging.StreamHandler):

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

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

Sie können dann den Logging-Handler vor der Ausführung von Tests wie folgt einrichten (dadurch wird der benutzerdefinierte Handler zum Root-Logger hinzugefügt):

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

Wenn Sie, wie ich, Ihre Tests in separaten Modulen haben, können Sie einfach eine Zeile nach den Importen der einzelnen Unit-Test-Module einfügen, die sicherstellt, dass die Protokollierung eingerichtet ist, bevor die Tests ausgeführt werden:

import logutil

logutil.setup_capturable_logging()

Das ist vielleicht nicht der sauberste Ansatz, aber er ist ziemlich einfach und hat bei mir gut funktioniert.

0voto

Wenn Sie verschiedene Initialisierungsmodule für Test, Entwicklung und Produktion haben, können Sie alles deaktivieren oder im Initialisierer umleiten.

Ich habe local.py, test.py und production.py, die alle von common.py erben

common.py übernimmt die gesamte Hauptkonfiguration einschließlich dieses Schnipsels:

    LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'django.server': {
            '()': 'django.utils.log.ServerFormatter',
            'format': '[%(server_time)s] %(message)s',
        },
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'require_debug_true': {
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler'
        }
    },
    'loggers': {
        'django': {
            'handlers': ['console'],
            'level': 'INFO',
            'propagate': True,
        },
        'celery.tasks': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True,
        },
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        },
    }

Dann habe ich in test.py folgendes:

console_logger = Common.LOGGING.get('handlers').get('console')
console_logger['class'] = 'logging.FileHandler
console_logger['filename'] = './unitest.log

Dies ersetzt den Konsolenhandler durch einen FileHandler und bedeutet, dass immer noch eine Protokollierung erfolgt, aber ich muss die Produktionscodebasis nicht berühren.

-2voto

Binh Ho Punkte 2247

Dies ist ein kleiner Hack, aber er funktioniert bei mir. Fügen Sie diesen Code ein, wenn Sie die erfassten Protokolle anzeigen möchten. Entfernen Sie ihn, wenn er nicht mehr benötigt wird.

self.assertEqual(1, 0)

def test_test_awesome_function():
    print("Test 1")
    logging.info("Test 2")
    logging.warning("Test 3")

    self.assertEqual(1, 0)

Aktualisiert:

Übrigens ist dies keine langfristige Lösung, sondern nur hilfreich, wenn Sie schnell etwas in den Zielfunktionen debuggen wollen.

Sobald die Durchsetzung fehlgeschlagen ist, unittest wird ausgeben, welche Funktionen Fehler machen und auch erfassen und anzeigen print , logging.* Inhalt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X