2010-05-06 19 views
6

Sto usando JUnit per scrivere alcuni test di livello superiore per il codice legacy che non ha test unitari.C'è un modo per forzare JUnit a fallire su QUALSIASI eccezione non controllata, anche se ingerita

Gran parte di questo codice "inghiotte" una varietà di eccezioni non controllate come NullPointerExceptions (ad es., Semplicemente stampando la traccia dello stack e restituendo null). Pertanto il test unitario può passare anche attraverso una cascata di disastri in vari punti del codice di livello inferiore.

C'è un modo per avere un errore di test sulla prima eccezione non controllata anche se vengono ingeriti?

L'unica alternativa che posso pensare è scrivere un wrapper JUnit personalizzato che reindirizza System.err e quindi analizza l'output per le eccezioni.

+4

No, come fa JUnit a sapere dell'eccezione se viene ingerita prima che venga raggiunto il codice JUnit? Ma forse non dovresti fare affidamento su tutto ciò che accade nel codice legacy e controllare che il tuo codice sia corretto.Dopo tutto, quando qualcosa va storto che ha un impatto sul risultato del codice, il test dovrebbe fallire. – FRotthowe

+0

@FRotthowe: sto utilizzando JUnit per scrivere test di regressione e test wrapper per i componenti esistenti del codice legacy. Non ho molto del mio codice. il problema è che voglio cogliere questi errori interni, soprattutto perché le persone mantengono il codice interno. – Uri

risposta

4

Se si eseguono i test nel debugger dell'IDE, è possibile configurare l'IDE da interrompere quando viene generata un'eccezione.

4

In mancanza di una soluzione concreta, di abbastanza generale la mia risposta: sono più puliti

Tale codice odori (ad esempio eccezioni swalling) passo dopo passo (classe per classe) quando li si incontra mentre fix dei bug del sistema legacy. Gli strumenti di qualità del codice (ad esempio Findbugs, PMD, Checkstyle o anche Sonar Quality Server) ti aiutano a trovare quelle cose.

Un modo per "catturare" le eccezioni ingerite automaticamente consiste nell'utilizzare il compilatore AspectJ. È possibile dichiarare gli aspetti per generare un errore in fase di compilazione nell'IDE quando alcune convenzioni di codice vengono violate. In alternativa, puoi tessere in runtime le classi sotto test e lasciare che AspectJ rilanci tali eccezioni, in modo che possano essere registrate dal runner JUnit.

+1

+1 - PMD ha già una regola per cercare blocchi di cattura vuoti. Probabilmente non sarebbe difficile estenderlo per fare in modo che le regole cerchino altri metodi comuni per fallire nella gestione delle eccezioni. –

0

Potrebbe essere possibile simulare le eccezioni che si desidera catturare con un framework di simulazione che modifica il bytecode o con un framework AOP. Immagino che potresti modificare il costruttore per lanciare un'eccezione più fatale, o per impostare qualche bandiera nel codice di test.

1

Credo che l'eccezione sia solo una classe standard nelle librerie SDK.

Se lo hai estratto, modificato e messo da qualche parte sul classpath prima dell'SDK, penso che dovrebbe sostituire quello nell'SDK (se non si potesse rimettere la tua "nuova" eccezione nel contenitore dell'SDK)

In ogni caso, la nuova eccezione potrebbe impostare un valore statico che può essere letto dal framework di test.

non può essere la soluzione più elegante ma non richiede alcuna "Magic"

+0

Non è così facile, dato che il codice è in java. pacchetto, e il JDK ha alcuni meccanismi di sicurezza per prevenire quel tipo di armeggiare che devi risolvere. – Yishai

+0

@Yishai Strange, ho conosciuto persone che lo fanno ma non hanno approfondito i meccanismi di ciò che hanno fatto. Dovrò esaminarlo ulteriormente ... (Dopo averlo guardato, questa pagina sembra non essere d'accordo: http://forums.sun.com/thread.jspa?threadID=30607&tstart=3420) –

+0

sì il percorso di classe di avvio è l'idea di base, ma ciò significherebbe una classe compilata e compilata separatamente racchiusa in un vaso separato, o qualche altro giochetto di fantasia per separare tali implementazioni, e quindi non si può avere quella classe interagire con altre classi (come una classe JUnit) e il tuo test deve chiamarlo, non viceversa. È fattibile, è così facile. – Yishai

1

Vorrei provare a utilizzare AOP per lanciare fallimenti. Qualcosa del genere dovrebbe funzionare (si noti, non ho ancora testato questo, e si obviouslly bisogno di avere il programma di installazione AspectJ per utilizzare le annotazioni AOP)

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

Forse è possibile incollare il codice che si stanno cercando di testare. Molto probabilmente dovresti usare alcuni dei framework di test "remapper" come powermock o jmockit per manipolare la manipolazione del classloader in JVM. Ma un campione di classe sotto test potrebbe aiutare a determinare l'approccio richiesto.

Problemi correlati