2012-04-13 13 views
12

In Java/Junit muss ich mit einem Objekt auf Null testen. Es gibt eine Vielzahl von Möglichkeiten, wie ich eine Bedingung testen kann, aber ich habe assertTrue für die meisten meiner Tests verwendet. Wenn ich in einem assertTrue nach Nullen suche, gibt EclEmma an, dass es nur einen Zweig testet.Fehlende Verzweigungen bei Verwendung von assertTrue anstelle von assertNull

Wenn ich die Anweisung manuell in eine Variable auflöse (z. B. das Ergebnis auf einen booleschen Wert setze und ihn in assertTrue übergebe), gilt die Codeabdeckung als abgeschlossen auf der Assert, aber nicht in der Variableninitialisierungszeile.

Warum passiert das? Bezieht sich dies auf den zusätzlichen Byte-Code, den Java scheinbar hinzufügt, wie unter http://sourceforge.net/apps/trac/eclemma/wiki/FilteringOptions erwähnt? Irgendwelche Lösungen (abgesehen von anderen assert-Anweisungen).

assertTrue:

assertTrue(myObject == null); //1 of 2 branches 

assertTrue:

boolean test = (myObject == null); //1 of 2 branches missing 
assertTrue(test); // complete 

assertNull:

assertNull(myObject) //complete; 
+1

Was durch die Verwendung assertNull null falsch ist mit der Durchsetzung? Es ist normalerweise besser, den entsprechenden Assert-Typ für das Asserted-Objekt zu verwenden. Sie sehen besser, was falsch ist, wenn der Test fehlschlägt, ohne zu viel in den Testcode zu graben. – nansen

+0

@nansen Das ist wahr, und ich habe kein Problem mit assertNull, wenn es eine Voraussetzung ist, aber IMO, alle behaupten "Typen" sind nur eine andere Form von assertTrue. Es kann zusätzliche Vorteile bei der Verwendung verschiedener Assert-Typen wie hinzugefügter Fehlerinformation/Lesbarkeit geben, aber das ist hier nicht wirklich ein Problem. –

+0

@nansen Das ist nicht zu sagen, dass ich AssertNull nicht verwenden und wahrscheinlich verwenden wird, fand ich gerade dieses spezielle Problem interessant, wie ich im Grunde für die gleiche Sache testen, aber Emma gibt völlig andere Ergebnisse. –

Antwort

16

Für die meisten Boolean expressi Der Java-Compiler generiert zusätzliche Zweige im Byte-Code. JaCoCo erzeugt "Branch Coverage" basierend auf dem generierten Byte-Code, nicht basierend auf dem ursprünglichen Java-Code, und zeigt daher zusätzliche Informationen zur Zweigabdeckung für fast jeden booleschen Ausdruck, den Sie verwenden würden.

In Ihrem Code ist der von Ihnen verwendete boolesche Ausdruck myObject == null.

Um diesen Wert zu berechnen, generiert der Java-Compiler Code, der die beiden Argumente auf dem Stapel verschiebt, und führt dann einen bedingten Sprung durch, um 1 (wahr) oder 0 (falsch) auf den Stapel zu schieben. JaCoCo meldet die Filialabdeckung dieses bedingten Sprungs.

Daher löst die Tatsache, dass Sie myObject == null verwenden, das von Ihnen beschriebene Verhalten aus.

Wie einige andere Beispiele, versuchen Sie dies:

boolean t = true; 
boolean f = false; 
boolean result1 = (t && f) || f; // 3 out of 6 missed. 
boolean result2 = !t;   // 1 out of 2 missed. 

Dies kann nützlich sein, wenn der boolesche Ausdruck ist, beispielsweise durch eine Funktion zurückgegeben, die als Bedingung in einer if-then-else-Anweisung verwendet wird irgendwo anders. Obwohl dies hauptsächlich eine Konsequenz der Funktionsweise des Java-Compilers ist, hilft es, die Bedingung Abdeckung (anstelle von nur Abdeckung Abdeckung) des ursprünglichen Java-Codes zu beurteilen.

Diese Funktion auch nicht gut dokumentiert, aber hier sind einige Hinweise:

So ist es in der Tat, mit dem zusätzlichen Byte-Code im Zusammenhang erzeugt wird, aber nicht auf die spezifischen Beispiele für synthetische Byte-Compiler-Konstrukte, für die die Filteroptionen bestimmt sind.

HINWEIS: Wurde Haupt EDIT seit der ersten Antwort zu viel geraten. Danke an @ ira-baxter für gute & kritische Diskussion.

1

Die Tatsache, dass Emma einen bedingten Ausdruck als "etwas mit einer Verzweigung" behandelt, um (Zweig-) Coverage Count IMHO scheint einfach gebrochen. Es ist keine bedingte Verzweigung.

Wir können mehr über die Assert argumentieren; Wenn es definiert wurde als "löst Ausnahme bei Fehler" aus, dann hat es wirklich eine bedingte Verzweigung; Wenn es so definiert ist [wie ich denke, ich bin kein Java-Experte] als "beende mein Programm bei fehlgeschlagenem Versehen", dann ist es nicht wirklich ein Zweig. Unklar sind auch Methodenaufrufe; Diese sind bedingte Verzweigungen in dem Sinne, dass, wenn die aufgerufene Methode eine Ausnahme auslöst, der Kontrollfluss nicht zum "Rest der Anweisung" fortfährt.

Unser Tool Java Test Coverage erhält die (Zweig-) Coverage-Analyse für solche Bedingungen "richtig".

+0

Die assertTrue/assertNull-Methoden der JUnit-API sind nicht speziell. Sie werfen nur einen java.lang.AssertionError, wenn die Bedingung nicht erfüllt ist. Dies steht nicht in direktem Zusammenhang mit dem 'assert'-Schlüsselwort von Java. – avandeursen

+0

Ich stimme zu, dass der Aufruf dieses Emma/JaCoCo-Features * Filialabdeckung * (sehr) verwirrend ist. (Separate) Überdeckungsinfo, die mir für jeden booleschen Ausdruck (Unterausdruck) sagt, ob er sowohl auf wahr als auch auf falsch ausgewertet hat, ist ein nützliches Merkmal. – avandeursen

+0

@avandeursen: das Bestimmen, ob jede * Bedingung * in einem Programm als "wahr" oder "falsch" ausgeübt wurde, ist keine Zweigabdeckung; es ist "Bedingungsdeckung". Sicherlich ist unser Tool nicht in der Lage, die Bedingungen zu erfüllen. Basierend auf dem Verständnis der Vergangenheit glaube ich nicht, dass Emma die Berichterstattung konditioniert, aber ich könnte überrascht sein. –

0

Zu 100% Code Coverage auf boolean Methoden zu erhalten, gehen Sie wie folgt

Class RecordService{ 


    public boolean doesRecordExist(String id){ 

    return id!=null; 

    } 


    } 

    //Method inside your mock 
    @Test 
    public boolean testDoesRecordExist(){ 
    RecordService recordService = mock(RecordService.class); 
    when(recordService.doesRecordExists()).thenReturn(
        anyString()).thenReturn(null); 

    }