2013-08-14 6 views
5

Wenn ich Testfälle für eine Funktion schreibe, die eine Reihe von Ausnahmen auslöst, sollte ich eine throws-Deklaration für diese Ausnahmen in meiner Testmethode hinzufügen Fange jede einzelne Ausnahme. Was ist der richtige Weg? Ich glaube, Try-Catch ist ein besserer Weg, aber im Catch-Block sollte ich den StackTrace drucken?Sollten jUnit-Testfälle Standardausnahmen in einer throws-Deklaration oder in einem try catch-Block behandeln

Zum Beispiel habe ich eine Methode getGroups(String name), die AuthenticationException wirft. Wenn ich einen Testfall schreibe, um zu überprüfen, ob eine IllegalArgumentException ausgelöst wird, wenn der Parameter name null ist, wie handhabe ich die AuthenticationException? Füge ich es zu einem Teil meiner Methode hinzu oder schließe die Ausnahme in einen try-catch Block ein.

@Test 
public void testGetGroupsWithNull() throws AuthenticationException { 
thrown.expect(IllegalArgumentException.class); 
getGroups(null); 
} 

In dem obigen Testfall habe ich nur eine throws AuthenticationException, aber ich würde gerne wissen, ob es besser ist, die Ausnahme in einem Try-Catch-Block zu umschließen und was shoudld ich tun, nachdem die Ausnahme zu kontrollieren. Ich könnte die Stapelverfolgung drucken.

Ich verarbeite die unerwartete Ausnahme AuthenticationException, indem ich sie nicht in die 'throws' Klausel setze, sondern in einen try/catch Block.

@Test 
public void testGetGroupsWithNull() { 
thrown.expect(IllegalArgumentException.class); 
try { 
    getGroups(null); 
} catch(AuthenticationExcption e) { 
    Assert.fail("Authentication Exception"); 
} 
} 
+0

Hat meine Antwort Ihnen geholfen oder Ihre Frage gelöst? –

Antwort

5

JUnit hat hier einen tollen Artikel: https://github.com/junit-team/junit/wiki/Exception-testing zu diesem Thema. Sie tun können:

@Test(expected= IndexOutOfBoundsException.class) 
public void empty() { 
    new ArrayList<Object>().get(0); 
} 

oder:

@Test 
    public void testExceptionMessage() { 
     try { 
      new ArrayList<Object>().get(0); 
      fail("Expected an IndexOutOfBoundsException to be thrown"); 
     } catch (IndexOutOfBoundsException anIndexOutOfBoundsException) { 
      assertThat(anIndexOutOfBoundsException.getMessage(), is("Index: 0, Size: 0")); 
     } 
    } 
1

Die Anmerkung kommunikativer ist.

Es signalisiert, was der Test erwartet passieren, ohne den Leser zu zwingen, den Code zu lesen.

Bei jedem einzelnen Test sollte nur eine einzelne Ausnahme erwartet werden, da jeder Test ein einzelnes Verhalten testen sollte. Ein einzelnes Verhalten kann nur eine Ausnahme auslösen.

Wenn eine andere Ausnahme ausgelöst wird, ist dies ein Testfehler. Die Signatur der Testmethode muss natürlich alle möglichen überprüften Ausnahmen widerspiegeln, genauso wie echte Code, der die gleiche Methode aufruft.

4

Wenn ein JUnit-Test eine unerwartete Ausnahme auslöst, schlägt er fehl. Das ist das Verhalten, das du willst. Es macht also keinen Sinn, einen try/catch-Block zu verwenden. Wenn Sie eine Ausnahme erwarten, verwenden Sie eine ExpectedException-Regel (von der Sie offensichtlich wissen, aus Ihrem Code-Snippet). Aber, ob Sie einen erwarten oder nicht, verwenden Sie nicht versuchen/fangen.

Das bedeutet, wenn Ihre Ausnahme eine geprüfte Ausnahme ist, benötigen Sie eine throws-Klausel. Tatsächlich benötigen Sie oft eine throws-Klausel für Ihre Testmethode, selbst wenn Sie NICHT erwarten, dass die Ausnahme ausgelöst wird, nur weil Ihr Test eine Methode aufruft, mit der SOMETIMES eine geprüfte Ausnahme auslösen kann. Ich habe es mir angewöhnt, throws Exception für jede einzelne Testmethode zu schreiben. Es gibt keinen Grund, nicht zu; und es ist nur eine Sache weniger, über die man sich Sorgen machen muss.

+0

Ich möchte nur sicherstellen, dass ich verstehe, was Sie sagen. In diesem speziellen Fall oder allgemein als "AuthenticationException" ist eine geprüfte Ausnahme, ich sollte die Ausnahme der "throws" -Klausel der Methode hinzufügen. Ich sollte diese Ausnahme nicht in einem try/catch-Block behandeln, da der Testfall bestanden wird, selbst wenn eine 'AuthenticationException' ausgelöst wird. – user12222

+1

In diesem speziellen Fall wird der Test fehlschlagen, wenn Sie die Ausnahme zusätzlich zur Behandlung mit einer ExpectedException-Regel behandeln. Das liegt daran, dass die ExpectedException-Regel dafür sorgt, dass eine Ausnahme wirklich ausgelöst und nicht abgefangen wird. Also, verwende try/catch nicht in dieser Testmethode, sonst wird es fehlschlagen. Und im Allgemeinen, verwenden Sie nicht versuchen/fangen in keiner Testmethode, weil es nicht notwendig ist, und fügt nur Rauschen zu Ihrem Test. –

+0

Ich bin jetzt ein bisschen verwirrt. Aber haben Sie nicht gesagt, dass das Verhalten eines JUnit-Tests fehlschlägt, wenn eine unerwartete Ausnahme auftritt? Wenn ich also der throws-Klausel der Methode 'AuthenticationException' hinzufüge, wird der Testfall bestanden, obwohl eine unerwartete Ausnahme ausgelöst wird. Wenn ich andererseits die unerwartete Ausnahme in einem try/catch-Block behandle und die Testmethode zwinge, eine unerwartete Ausnahme auszulösen, schlägt der Test fehl. – user12222

1

Mit der Regel, so wenig Code wie möglich zu schreiben, um das Problem zu lösen, gewinnt Ihr erstes Code-Snippet. Also, setzen Sie die AuthenticationException in die throws Klausel Ihrer Testmethode. Es ist prägnanter und lesbarer.

0

Ich habe nur nach der gleichen Frage gesucht, da ich mich mit Ihrem Thema befasse und ich eine gute Erklärung für Best Practices für Unit Tests gefunden habe. Ein kleiner Auszug aus dem Artikel kann Ihnen helfen.

Es ist nicht notwendig, eigene Catch-Blöcke zu schreiben, die nur für einen Test fehlschlagen, weil das JUnit-Framework die Situation für Sie erledigt. Zum Beispiel: Angenommen, Sie Unit-Tests für die folgende Methode schreiben:

final class Foo { 
    int foo(int i) throws IOException; 
} 

Hier haben wir eine Methode, die eine ganze Zahl und gibt eine ganze Zahl annimmt und eine IOException aus, wenn ein Fehler auftritt. Hier ist der falsche Weg, um ein Gerät zu testen zu schreiben, das bestätigt, dass die Methode drei zurückgibt, wenn sieben bestanden:

// Don't do this - it's not necessary to write the try/catch! 
@Test 
public void foo_seven() 
{ 
    try 
    { 
    assertEquals(3, new Foo().foo(7)); 
    } 
    catch (final IOException e) 
    { 
    fail(); 
    } 
} 

Die Methode im Test gibt an, dass es IOException werfen kann, die eine geprüfte Ausnahme ist. Daher wird der Komponententest nicht kompiliert, es sei denn, Sie fangen die Ausnahme ab oder deklarieren, dass die Testmethode die Ausnahme verbreiten kann. Die zweite Alternative bevorzugt, weil sie in kürzeren und stärker fokussierten Testergebnisse:

// Do this instead 
@Test 
public void foo_seven() throws Exception 
{ 
    assertEquals(3, new Foo().foo(7)); 
} 

Wir erklären, dass die Testmethode throws Exception statt throws IOException. Das JUnit-Framework stellt sicher, dass dieser Test fehlschlägt, wenn während des Aufrufs der zu testenden Methode eine Ausnahme auftritt. Es ist nicht erforderlich, eine eigene Ausnahmebehandlung zu schreiben.

Sie können in diesem Artikel, wie oben mehr über JUnit Best Practices finden: http://www.kyleblaney.com/junit-best-practices/

Hoffnung zu helfen.

Verwandte Themen