2012-08-17 12 views
16

Es ist üblich Logging-Funktionalität im CodeSollten wir die Testprotokollierung zusammenführen?

public class A { 

private static final Log LOG = LogFactory.getLog(A.class); 

und Nutzung

 } catch (Exception e) { 
      LOG.error(e.getMessage(), e); 
      throw e; 
     } 

aber ich habe nie gesehen, auch einzelne Einheit Test für einen solchen Code zu sehen.

Natürlich teste ich Wurf Ausnahme und Ausnahme Typ, aber sollte ich Test für die Überprüfung der Protokollierung Informationen schreiben? Ich neige dazu, zu denken, dass Logging ein weiterer Teil des Systemverhaltens ist, also ist es logisch, es in den Tests abzudecken.

Angenommen, dass ich es abdecken sollte, bedeutet, dass ich meinen ursprünglichen Code ändern sollte, um Mock-Protokoll einzufügen und zu überprüfen, dass die "Fehler" -Methode mit der erwarteten Nachricht aufgerufen wurde. Aber was tun, wenn meine ursprüngliche Klasse Dienst ist und im Frühjahr instanziiert wird, sollte ich etwas Logger sowie andere Abhängigkeiten injizieren?

Antwort

9

Es liegt nicht an Ihnen, die Protokollierungsbibliothek zu testen. Es kann sich jedoch lohnen zu testen, dass Ihre Klasse eine Nachricht auf der richtigen Ebene protokolliert, wenn eine Ausnahme ausgelöst wird. Was Sie testen, ist, dass Ihr Code mit der Protokollierungsbibliothek das Richtige tut.

Um den obigen Code testbar zu machen, verwenden Sie die Abhängigkeitsinjektion. Dies setzt voraus, dass der Logger eine Schnittstelle implementiert, ILog. Sie würden den Logger als Konstruktorparameter an die Klasse A übergeben. Dann würde der Testcode eine Scheinimplementierung von ILog erstellen und diese an den Konstruktor übergeben. Im obigen Code wird nicht gezeigt, wie die Ausnahme zustande kommt, aber vermutlich durch ein anderes abhängiges Objekt. Also verspotten Sie das auch und lassen es eine Ausnahme machen. Überprüfen Sie dann, ob der Schein ILog die Methode error aufgerufen hat. Vielleicht möchten Sie die Nachricht untersuchen, die sie protokolliert, aber das könnte zu weit gehen, indem Sie den Testcode fragil machen.

+0

ist es der gleiche Ansatz, den ich in meiner Frage erwähnt habe. Aber für mich ist es immer noch unklar, was man bei Frühlingsdiensten tun sollte, da normalerweise LOG für jede Klasse erstellt wurde, also ist es klassenspezifisch und ich kann es nicht als Singleton machen. –

+0

Wenn Sie keine Kontrolle über den Code haben, der das Log-Objekt instanziiert, ist es schwierig, das Verhalten zu testen, da Sie kein Scheinprotokoll verwenden können. Sie könnten es mit dem echten Log-Objekt protokollieren lassen und dann prüfen, ob eine Nachricht protokolliert wurde. Das ist jedoch schwer zu automatisieren! –

+0

Nein, ich stimme Ihnen zu, dass der Protokollierungscode getestet werden sollte. Dann heißt das, dass wir LOG einrichten sollten, so dass es möglich ist, Scheinanmeldungs-Tests zu bestehen, aber was man im Falle von Frühlingsdiensten tun sollte. Ich denke über 2 mögliche Wege nach: 1) habe einen Setter, aber rufe nur aus Tests auf (könnte schwierig sein, solche Sichtbarkeit einzuschränken, da der Frühling eine automatische Injektion machen könnte), 2) Logger durch Feder injizieren, aber in diesem Fall ist es schwer instanziieren Sie den richtigen Logger. –

2

Ich würde Testcode nicht einbinden, der nur in eine Bibliothek ruft, der Sie vertrauen.
Vertrauen Sie Ihrer Protokollierungsbibliothek? Wenn der Test fehlschlägt, liegt es an einem Fehler in der Bibliothek oder daran, dass Sie die Bibliothek nicht korrekt konfiguriert haben? Haben Sie Pflege zum Testen der Konfiguration?

+14

Ich nicht testen, wie Logging-Bibliothek funktioniert, meine Absicht ist zu testen, dass mein Code Protokollierung. –

1

Ja, wir sollten die Protokollierung testen, wenn die Protokollierung etwas benötigt. Zum Beispiel haben Sie Haken in einer externen Anwendung, die das Protokoll nach bestimmten Ereignissen durchsucht. In diesem Fall möchten Sie sicher stellen, dass die Protokollierung durchgeführt wird.

Natürlich möchten Sie nicht jedes Logging-Ereignis testen, und ich würde denken, dass meistens nur FEHLER (und nicht alle von ihnen) getestet werden sollten.

Mit modernen Logging-Frameworks wie SLF4j können Sie einfach einen benutzerdefinierten Handler injizieren, der die Ereignisse für den Arbeitsspeicher speichert und die anschließend aktiviert werden können.

Es gibt zwei von ihnen, die jetzt zu meinem Sinn kommen:

SLF4JTesting: keine Änderung der Protokollierung Konfiguration erfordert, erfordert aber eine Protokollierung Fabrik zu injizieren, die zu geänderten Code führen könnten.

SLF4J Test: Nicht so mächtig wie slf4jtesting und scheint nicht entwickelt zu werden, funktioniert aber gut mit bestehenden Code. Keine Änderungen außer der Logger-Konfiguration für den Test.

Bei der Verwendung von SLF4J Test sind die Assertions relativ streng und überprüfen das gesamte Ereignis auf Gleichheit. Eine benutzerdefinierte Matcher ist wahrscheinlich interessant in einem solchen Fall:

public static Matcher<LoggingEvent> errorMessageContains(final String s) { 
    return new TypeSafeMatcher<LoggingEvent>() { 
     @Override 
     public void describeTo(final Description description) { 
      description.appendText(" type " + Level.ERROR + " should contain ") 
        .appendValue(s); 
     } 

     @Override 
     protected void describeMismatchSafely(final LoggingEvent item, final Description mismatchDescription) { 
      mismatchDescription.appendText(" was type ").appendValue(l) 
        .appendText(" message ").appendValue(item.getMessage()); 
     } 

     @Override 
     protected boolean matchesSafely(final LoggingEvent item) { 
      return item.getLevel().equals(Level.ERROR) 
        && item.getMessage().contains(s); 
     } 
    }; 
} 

Diese prüft nur, dass die Nachricht enthält einen Text, aber nicht, wenn es gleich ist. Wenn die Nachricht modifiziert wird, um einen Tippfehler zu beheben oder mehr Details zu geben, wird der Test nicht unterbrochen, wenn der wesentliche Teil noch enthalten ist.

0

Wenn die Protokollierung eine geschäftliche Anforderung ist und einen Geschäftswert liefert (z. B. im Falle eines Fehlers, Diagnose oder Triage eines Problems), sollten Sie sie wie jede andere Anforderung behandeln. Daher sollten Sie wahrscheinlich Komponententests schreiben, um nicht zu überprüfen, ob Ihre Protokollierungsbibliothek funktioniert, sondern um sicherzustellen, dass Ihr Code unter den zu erwartenden Umständen protokolliert, was er sollte.

Mehr zu diesem Thema: https://ardalis.com/logging-and-monitoring-are-requirements

0

gibt es einen anderen Weg: Sie können LogFactory spotten! zum beispiel:

import junit.framework.Assert; 
import mockit.Mock; 
import mockit.MockUp; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.junit.Test; 

public class XXXTest { 
    class MyLog implements Log { 
     public static final String INFO = "info"; 

     private String logLevel; 
     private Object logContent; 

     public String getLogLevel() { 
      return logLevel; 
     } 

     public Object getLogContent() { 
      return logContent; 
     } 

     @Override 
     public void info(Object o) { 
      logLevel = "info"; 
      logContent = o; 
     } 

     //Implement other methods 
    } 

    @Test 
    public void testXXXFunction() { 
     final MyLog log = new MyLog(); 
     new MockUp<LogFactory>() { 
      @Mock 
      public Log getLog(String name) { 
       return log; 
      } 
     }; 

     //invoke function and log by MyLog 
     FunctionToBeTest.invoke(); 
     Assert.assertEquals("expected log text", log.getLogContent()); 
    } 
} 

viel glück!

Verwandte Themen