it-swarm.com.de

Versuchen Sie, in einem JUnit-Test zu erfassen

Ich schreibe Unit-Tests für eine Anwendung, die schon lange existiert. Einige der Methoden, die ich testen muss, sind wie folgt aufgebaut:

public void someMethod() throws Exception { 
   //do something 
}

Wenn ich diese Methoden testen möchte, muss ich im Komponententest Folgendes schreiben:

@Test
public void someTest() {
   try {
      someMethod();
   }
   catch (Exception e) {
      e.printStackTrace();
   }
}

Ist es eine gute Praxis, dies zu tun? Oder gibt es eine andere Möglichkeit, diese Methoden zu testen?

Ich habe im Internet etwas recherchiert und ein paar Lösungen mit der @Rule-Annotation und @Test(expected=Exception.class) gefunden, aber das funktioniert nicht (Eclipse zeigt die someMethod()-Zeile im Test immer als falsch an) Lösungen, weil ich für die gesamte Unit-Test-Story ziemlich neu bin.

Wenn jemand, der viel darüber weiß, mir helfen könnte, wäre ich wirklich dankbar.

46
Nelsch

Da Exception eine geprüfte Ausnahme ist, haben Sie entweder:

  • Müssen Sie die Ausnahme in einer try...catch-Anweisung abfangen, oder
  • Deklarieren Sie die Ausnahme, die in der Methode selbst ausgelöst werden soll.

Was Sie dort oben haben, funktioniert gut, aber meine persönliche Präferenz ist es, die Ausnahme für ausgelöst zu erklären. Auf diese Weise wird, wenn eine Ausnahme, die ich nicht erwarte, während des Testlaufs ausgelöst wird, der Test fail.

@Test
public void someTest() throws Exception {
    // dodgy code here
}

Wenn wir feststellen müssen, ob eine bestimmte Ausnahme ausgelöst wird, haben Sie die Möglichkeit, @Rule zu verwenden oder den Wert direkt zur @Test-Annotation hinzuzufügen.

@Test(expected = FileNotFoundException.class)
public void someTest() throws Exception {
    // dodgy code here
}

In JUnit 5 können Sie Assertions.expectThrows verwenden, um dasselbe zu erreichen. Ich bin mit diesem Gesamtbild weniger vertraut, da es zum Zeitpunkt der Bearbeitung noch nicht GA ist, aber es scheint eine Executable von JUnit 5 zu akzeptieren.

@Test
public void someTest() {
    assertThrows(FileNotFoundException.class, () ->
         { dodgyService.breakableMethod() };
}
61
Makoto
@Test
public void someTest() {
   try {
     someMethod();
   }
   catch (Exception e) {
     Assert.fail("Exception " + e);
   }
}

Ist das, was Sie tun können, wenn die Ausnahme nicht auftreten sollte. Eine Alternative wäre, die Ausnahme wie folgt in die Signatur zu werfen:

@Test
public void someTest() throws Exception {
     someMethod();
}

Der Unterschied ist, dass in einem Fall der Test mit einer Assertionsausnahme fehlschlägt und im anderen Fall der Test fehlschlägt, weil der Test abgestürzt ist. (Wie irgendwo in deinem Code bekommst du eine NPE und der Test wird deswegen so)

Der Grund dafür ist, dass Exception eine geprüfte Exception ist. See Checked vs. ungeprüfte Ausnahme

Das @Test (erwartet = Exception.class) ist für Tests gedacht, die testen möchten, dass die Ausnahme ausgelöst wird. 

@Test(expected=ArrayIndexOutOfBounds.class)
public void testIndex() {
   int[] array = new int[0];
   int var = array[0]; //exception will be thrown here, but test will be green, because we expect this exception

}
22
morpheus05

Fangen Sie die Ausnahme Ihrer Anwendung nicht in Ihrem Testcode ab. Erklären Sie es stattdessen, um nach oben geworfen zu werden.

Wenn JUnits TestRunner eine ausgelöste Ausnahme feststellt, wird diese automatisch als error für den Testfall protokolliert.

Nur wenn Sie testcase erwarten, dass die Methode eine Exception ausgelöst hat, sollten Sie @Test(expected=Exception.class) verwenden oder die Ausnahme abfangen.

In anderen Fällen werfen Sie es einfach nach oben mit

public void someTest() throws Exception {
6
Codebender

Sie können eine Ausnahme in der Testmethodensignatur hinzufügen. Wenn Sie dann testen, ob eine Ausnahme ausgelöst wird, müssen Sie @Test(expected=Exception.class) verwenden. In den Testfällen, in denen keine Ausnahme ausgelöst werden muss, wird der Test erfolgreich bestanden. 

@Test
public void testCaseWhereExceptionWontBeThrown() throws Exception {
    someMethod(); //Test pass
}

@Test(expected = Exception.class)
public void testCaseWhereExceptionWillBeThrown() throws Exception {
    someMethod(); //Test pass
}
6
Héctor

Es gibt zwei Hauptregeln für die Verarbeitung von Ausnahmen bei Junit-Testern:

  1. Wenn die Ausnahme im getesteten Code entstanden ist:

    • Wenn dies erwartet wurde, deklarieren Sie es im expected-Attribut der Test-Annotation. Wenn weitere Prüfungen am Ausnahmeobjekt selbst durchgeführt werden sollen, fangen Sie es ab und ignorieren Sie es. (In diesem Fall muss auch Assert.fail am Ende des try-Blocks aufgerufen werden, um anzuzeigen, dass die erwartete Ausnahme nicht erzeugt wurde.).
    • Wenn es nicht erwartet wurde, fangen Sie es ab und führen Sie Assert.fail aus. (Ein vorheriger Aufruf von Exception.printStackTrace ist ebenfalls hilfreich).
  2. Wenn die Ausnahme nicht aus dem getesteten Code stammt oder für den Test nicht interessant ist (z. B. werden die meisten IOExceptions auf Netzwerkebene erstellt, bevor der Test sogar abgeschlossen werden konnte), erneut an der Variablen throws Klausel.

  3. </ p></ li>

Warum sollten Sie beim Tester eine Ausnahme erwarten? Erinnern: Sie sollten eine Testmethode für jedes mögliche Ergebnis des getesteten Codes codieren (um eine hohe Codeabdeckung zu erreichen): In Ihrem Fall eine Methode, die erfolgreich zurückgegeben werden muss, und mindestens eine andere Methode, die produziert werden muss eine Ausnahme.

3
Little Santi

Drei Punkte zu JUnit:

  • Tests sollten präzise sein, sie sollten eindeutig bestanden werden oder fehlschlagen, und zwar ausschließlich aufgrund der Einrichtung der Testeingaben.

  • Bei Tests sollten Fehler in das Framework zurückgemeldet werden.

  • Tests sollten sich nicht darauf verlassen, dass ihre Ausgabe gelesen wird.

Ihr Beispiel versagt in allen drei Punkten. Wenn eine Ausnahme ausgelöst wird oder nicht, ist der Test noch erfolgreich. Wenn eine Ausnahme ausgelöst wird, findet JUnit dies nicht und kann sie nicht in die Testergebnisse aufnehmen. Der einzige Weg, um zu wissen, dass etwas schief gelaufen ist, besteht darin, zu lesen, was der Test in stdout schreibt. Dadurch werden Fehler zu einfach ignoriert. Dies ist keine nützliche Methode zum Schreiben von Tests.

JUnit wurde entwickelt, um das Richtige zu vereinfachen und Entwicklern nützliches Feedback zu geben. Wenn eine Ausnahme von einer Testmethode geworfen wird, wird sie vom Framework erfasst. Wenn der Test mit einer Ausnahme kommentiert wurde, die angibt, dass eine Ausnahme erwartet wird, kennzeichnet das Framework den Test als bestanden. Andernfalls schlägt das Framework den Test fehl und zeichnet das Stacktrace für die Berichterstellung auf. Das Framework meldet, welche Zusicherungen fehlschlagen und welche unerwarteten Ausnahmen aufgetreten sind, sodass jeder weiß, ob die Tests erfolgreich waren oder nicht. 

Wenn Sie davon ausgehen, dass ein Test erfolgreich ist, ohne eine Ausnahme auszulösen, fügen Sie throws Exception zur Testmethodensignatur hinzu, wenn im Test eine geprüfte Ausnahme ausgelöst werden kann. Das Hinzufügen der Variable throws zur Signatur bedeutet nicht, dass die Methode muss etwas auslösen muss. Es werden lediglich alle Ausnahmen ausgelöst, die auftreten, sodass das Testframework sie fangen kann.

Der einzige Fall, in dem Sie die Ausnahme im Test tatsächlich einfangen würden, ist der, in dem Sie Assertions über die Ausnahme testen möchten. Sie können beispielsweise testen, ob die Nachricht für die Ausnahme das ist, was Sie erwarten, oder ob für die Ausnahme eine Ursache festgelegt ist. In diesem Fall würden Sie am Ende des try-Blocks Assert.fail() hinzufügen, so dass der Test fehlschlägt, wenn keine Ausnahme ausgelöst wird.

Wenn Sie zuerst einen Test schreiben, kann der Test fehlschlagen. Auf diese Weise beweisen Sie sich selbst, dass Sie wissen, was der Test macht, und Sie bestätigen, dass Sie bei einem Ausfall darauf aufmerksam gemacht werden.

Was für eine Ausnahme ist das? Ist es

  1. eine Ausnahme von der Verwendung von Streams, die in Ihrem Gerätetest oder nicht auftreten
  2. eine ausnahme, die aufgrund einer fehlerhaften eingabe auftreten kann?

Wenn es 1. ist, würde ich es einfach auf die Methodensignaturebene setzen, weil ein Try-Catch keinen echten Zweck erfüllt, außer der Zeremonie.

@Test
public void testFoo() throws Exception {
    // ...
}

Wenn es 2. ist, wird es etwas komplizierter. Sie müssen sich fragen, was passieren soll, wenn die Ausnahme ausgelöst wird. Sollte der Test fehlschlagen? Wird es erwartet? Ist es irrelevant? Beispiele für den Umgang mit all diesen. BEWARE: Ich habe Exception nur benutzt, weil du es getan hast. Ich hoffe, dass es nicht wirklich der Fall ist, denn wenn eine andere-Ausnahme anders als erwartet geworfen werden kann, werden diese sehr wacklig. Verwenden Sie nach Möglichkeit nicht Exception, sondern verwenden Sie etwas spezifischeres (im junit und Code).

// The below code assumes you've imported the org.junit.Assert class.

@Test
public void thisShouldFailIfExceptionCaught() {
    //Given...
    try {
        // When...
    } catch (Exception e) {
        Assert.fail();
    }
    // Then...
}

@Test
public void thisShouldPassOnlyIfTheExceptionIsCaught() {
    //Given...
    try {
        // When...
        Assert.fail();
    } catch (Exception expected) {}
    // No "then" needed, the fact that it didn't fail is enough.
}

@Test
public void irrelevantExceptionThatCouldBeThrown() {
    //Given...
    try {
        // When...
    } catch (Exception e) {}
    // Then...
}
0
Captain Man