2010-05-06 6 views
6

Ich benutze JUnit, um einige höhere Level-Tests für Legacy-Code, der keine Unit-Tests hat schreiben.Gibt es eine Möglichkeit, JUnit zu zwingen, bei jeder ungeprüften Ausnahme fehlschlagen, auch wenn verschluckt

Ein Großteil dieses Codes "schluckt" eine Vielzahl von ungeprüften Ausnahmen wie NullPointerExceptions (z. B. indem nur die Stapelverfolgung gedruckt und null zurückgegeben wird). Daher kann der Komponententest selbst durchlaufen, da es an verschiedenen Stellen im unteren Code eine Kaskade von Katastrophen gibt.

Gibt es eine Möglichkeit, einen Test für die erste ungeprüfte Ausnahme fehlschlagen zu lassen, selbst wenn sie verschluckt wird?

Die einzige Alternative, die ich denken kann, ist, einen benutzerdefinierten JUnit-Wrapper zu schreiben, der System.err umleitet und dann die Ausgabe nach Ausnahmen analysiert.

+4

Nein, wie würde JUnit von der Ausnahme wissen, wenn sie verschluckt wird, bevor der JUnit-Code erreicht wird? Aber vielleicht sollten Sie sich nicht auf irgendetwas verlassen, was im Legacy-Code passiert, und einfach überprüfen, ob Ihr Code korrekt ist.Denn wenn etwas schief geht, was sich auf das Ergebnis Ihres Codes auswirkt, sollte Ihr Test fehlschlagen. – FRotthowe

+0

@FRotthowe: Ich verwende JUnit, um Regressionstests und Wrapper-Tests für vorhandene Komponenten des Legacy-Codes zu schreiben. Ich habe nicht viel von meinem eigenen Code. Das Problem ist, dass ich diese internen Fehler abfangen möchte, vor allem wenn die Leute den internen Code pflegen. – Uri

Antwort

4

Wenn Sie die Tests im IDE-Debugger ausführen, können Sie die IDE so konfigurieren, dass sie bricht, wenn eine Ausnahme ausgelöst wird.

4

In Fehlen einer konkreten Lösung, ist meine Antwort ziemlich allgemein:

Solche Code riecht (z Swalling Ausnahmen) werden am besten Schritt für Schritt (Klasse nach Klasse) gereinigt, wenn Sie sie treffen, während das Altsystem Bugfixing. Code-Qualitätstools (z. B. Findbugs, PMD, Checkstyle oder sogar Sonar Quality Server) helfen Ihnen, diese Dinge zu finden.

Eine Möglichkeit, automatisch geschluckte Ausnahmen automatisch zu "fangen", ist die Verwendung des AspectJ-Compilers. Sie können Aspekte zum Generieren eines Kompilierungsfehlers in Ihrer IDE deklarieren, wenn bestimmte Code-Konventionen verletzt werden. Alternativ können Sie die zu testenden Klassen zur Laufzeit weben und AspectJ solche Ausnahmen erneut auslösen lassen, damit sie vom JUnit-Runner aufgezeichnet werden können.

+1

+1 - PMD hat bereits eine Regel, um nach leeren Catch-Blöcken zu suchen. Es wäre wahrscheinlich nicht schwer, dies zu erweitern, um Regeln zu erstellen, nach anderen üblichen Möglichkeiten zu suchen, bei der Ausnahmebehandlung zu versagen. –

0

Es könnte möglich sein, die Ausnahmen, die Sie fangen wollen, mit einem spöttischen Framework zu verspotten, das den Bytecode modifiziert, oder mit einem AOP-Framework. Ich stelle mir vor, Sie könnten den Konstruktor ändern, um eine schwerwiegendere Exception auszulösen oder ein Flag in Ihrem Testcode zu setzen.

1

Ich glaube, Ausnahme ist nur eine Standardklasse in den SDK-Bibliotheken.

Wenn Sie es extrahiert, geändert und irgendwo auf Ihrem Klassenpfad vor dem SDK abgelegt haben, denke ich, dass es das im SDK ersetzen sollte (Wenn Sie Ihre "neue" Ausnahme nicht in das SDK-Jar zurückstellen könnten)

Ihre neue Ausnahme könnte jedoch einen statischen Wert festlegen, der vom Testframework gelesen werden kann.

vielleicht nicht die eleganteste Lösung, aber es erfordert keine „Magic“

+0

Das ist nicht so einfach, wie der Code in einem Java ist. Paket, und das JDK hat einige Sicherheitsmechanismen, um diese Art von Basteln zu verhindern, dass Sie umgehen müssen. – Yishai

+0

@Yishai Seltsam, ich habe Leute gekannt, die es tun, aber ich habe mich nicht in die Mechanik dessen vertieft, was sie getan haben. Ich muss weiter darüber nachdenken ... (Nach dem Betrachten scheint diese Seite nicht zu stimmen: http://forums.sun.com/thread.jspa?threadID=30607&tstart=3420) –

+0

Ja, der Boot-Klassenpfad ist die Grundidee, aber das würde eine separat hergestellte und kompilierte Klasse bedeuten, die in einem separaten Jar eingewickelt ist, oder eine andere schlaue Art, diese Implementierungen zu trennen, und dann kann diese Klasse nicht mit anderen Klassen interagieren (wie eine JUnit-Klasse) und dein Test muss es nennen, nicht umgekehrt. Es ist machbar, es ist einfach so einfach. – Yishai

1

Ich würde versuchen, AOP zu verwenden, Fehler zu werfen. So etwas sollte funktionieren (beachten Sie, ich habe nicht getestet, und Sie müssen obviouslly AspectJ Setup haben AOP Anmerkungen verwenden)

public class ClassUnderTest 
{ 
    private static Boolean exceptionThrown; 


    @Before 
    public void resetExceptionFlag() 
    { 
     ClassUnderTest.exceptionThrown = false; 
    } 

    @Test 
    public void myTestMethod() 
    { 

     //.... 
     // My Test Exception Code 
     //.... 

     assertFalse(ClassUnderTest.exceptionThrown); 
    } 

    @Aspect 
    static class TestAspects 
    { 
     @Pointcut("handler(Exception)") 
     public void intereceptAllExceptions(){} 

     //This is Fully Qualified because of the conflict with the junit Before annotation above 
     @org.aspectj.lang.annotation.Before("intereceptAllExceptions()") 
     public void flagExceptionThrown() 
     { 
     ClassUnderTest.exceptionThrown = true; 

    } 

} }

0

Vielleicht können Sie den Code einzufügen, die Sie versuchen zu testen. Meistens müssten Sie einige "Remapper" -Testframeworks wie powermock oder jmockit verwenden, um die Manipulation des Klassenladers in JVM zu manipulieren. Eine Probe der zu testenden Klasse würde jedoch helfen, den erforderlichen Ansatz zu bestimmen.