JUnit Verwirrung: Verwenden Sie 'erweitert TestCase' oder '@Test'?

152

Ich fand die richtige Verwendung (oder zumindest die Dokumentation) von JUnit sehr verwirrend. Diese Frage dient sowohl als zukünftige Referenz als auch als echte Frage.

Wenn ich richtig verstanden habe, gibt es zwei Hauptansätze zum Erstellen und Ausführen eines JUnit-Tests:

Ansatz A (JUnit 3-Stil): Erstellen Sie eine Klasse, die TestCase erweitert, und starten Sie die Testmethoden mit dem Wort test. Wenn Sie die Klasse als JUnit-Test (in Eclipse) testausführen , werden alle Methoden, die mit dem Wort beginnen, automatisch ausgeführt.

import junit.framework.TestCase;

public class DummyTestA extends TestCase {

    public void testSum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Ansatz B (JUnit 4-Stil): Erstellen Sie eine 'normale' Klasse und stellen Sie @Testder Methode eine Anmerkung voran . Beachten Sie, dass Sie die Methode NICHT mit dem Wort starten müssen test.

import org.junit.*;
import static org.junit.Assert.*;

public class DummyTestB {

    @Test
    public void Sum() {
        int a = 5;
        int b = 10;
        int result = a + b;
        assertEquals(15, result);
    }
}

Das Mischen der beiden scheint keine gute Idee zu sein, siehe z. B. diese Frage zum Stapelüberlauf :

Nun meine Fragen:

  1. Was ist der bevorzugte Ansatz oder wann würden Sie einen anstelle des anderen verwenden?
  2. Ansatz B ermöglicht das Testen auf Ausnahmen, indem die Annotation @Test wie in erweitert wird @Test(expected = ArithmeticException.class). Aber wie testen Sie bei Verwendung von Ansatz A auf Ausnahmen?
  3. Bei Verwendung von Ansatz A können Sie eine Reihe von Testklassen in einer Testsuite wie folgt gruppieren:

    TestSuite suite = new TestSuite("All tests");
    suite.addTestSuite(DummyTestA.class);
    suite.addTestSuite(DummyTestAbis.class);

    Dies kann jedoch nicht mit Ansatz B verwendet werden (da jede Testklasse TestCase unterklassifizieren sollte). Was ist der richtige Weg, um Tests für Ansatz B zu gruppieren?

Bearbeiten: Ich habe die JUnit-Versionen zu beiden Ansätzen hinzugefügt

Rabarberski
quelle
Ich habe gesehen extends TestCase und dann jeden Test auch kommentiert, @Testnur um die Dinge zu verwirren. :)
EM-Creations

Antworten:

119

Die Unterscheidung ist ziemlich einfach:

  • Erweitern TestCaseist die Art und Weise, wie Unit-Tests in JUnit 3 geschrieben wurden (natürlich wird es in JUnit 4 weiterhin unterstützt).
  • Die Verwendung der @TestAnnotation wird von JUnit 4 eingeführt

Im Allgemeinen sollten Sie den Anmerkungspfad auswählen, es sei denn, Kompatibilität mit JUnit 3 (und / oder einer früheren Java-Version als Java 5) ist erforderlich. Der neue Weg hat mehrere Vorteile:

Um in einer JUnit 3 auf erwartete Ausnahmen zu testen, müssen TestCaseSie den Text explizit angeben.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 führte eine weitere API-Änderung ein, verwendet jedoch weiterhin Anmerkungen. Die neue @TestAnnotation ist org.junit.jupiter.api.Test(die "alte" war JUnit 4 org.junit.Test), funktioniert aber fast genauso wie die JUnit 4.

Joachim Sauer
quelle
Hilfreiche und gründliche Antwort, aber ich verstehe "Prüfung auf Ausnahmemeldung" nicht vollständig. Das Überprüfen gegen eine fest codierte Zeichenfolge wird ein Alptraum für die Wartung sein. Sie müssen gemeint haben "Überprüfen Sie die Eigenschaften Ihres spezifischen Ausnahmetyps".
thSoft
3
@thSoft: Es kommt nicht oft vor, dass es verwendet wird, aber gelegentlich möchte ich sicherstellen, dass die Ausnahmemethode beispielsweise das fehlerhafte Feld erwähnt. Dann könnte ein einfaches assertTrue(e.getMessage().contains("foo"))nützlich sein.
Joachim Sauer
1
Selbst in JUnit4 ist dies eine wichtige Redewendung, wenn Sie die Nachricht oder eine andere Eigenschaft der Ausnahme (z. B. die Ursache) überprüfen müssen. Die expectedMethode prüft nur den Typ.
Yishai
@Yishai: Das stimmt, aber die meiste Zeit bin ich bereits zufrieden, wenn die Methode bei problematischen Eingaben den richtigen Ausnahmetyp auslöst.
Joachim Sauer
Aus diesem Grund hat JUnit 5 beim Testen von Ausnahmen eine grundlegende Änderung vorgenommen. assertThrows () ist fantastisch :-)
Marcus K.
25

Ich bevorzuge JUnit 4 (Annotation-Ansatz), weil ich es flexibler finde.

Wenn Sie eine Testsuite in JUnit 4 erstellen möchten, müssen Sie eine Klasse erstellen, die alle Tests wie folgt gruppiert:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({
    Test1.class,
    Test2.class,
    Test3.class,
    Test4.class
})public class TestSuite
{
 /* empty class */
}
Grimmy
quelle
15

Ihre Frage enthält einen unbeantworteten Teil: "Wie lassen sich Tests für Ansatz B richtig gruppieren?"

Die offizielle Antwort lautet, dass Sie eine Klasse mit einem @ RunWith (Suite.class) kommentieren und dann die Annotation @ Suite.SuiteClasses verwenden, um die Klassen aufzulisten. So machen es die JUnit-Entwickler (manuelle Auflistung jeder Klasse in einer Suite). In vielerlei Hinsicht ist dieser Ansatz insofern eine Verbesserung, als es trivial und intuitiv ist, Verhaltensweisen vor und nach der Suite hinzuzufügen (fügen Sie der mit @RunWith annotierten Klasse einfach eine @ BeforeClass- und eine @ AfterClass-Methode hinzu - viel besser als das alte TestFixture ).

Es gibt jedoch einen Rückschritt, da Sie mit Anmerkungen die Liste der Klassen nicht dynamisch erstellen können und das Umgehen dieses Problems etwas hässlich wird. Sie müssen die Suite-Klasse in Unterklassen unterteilen und das Array von Klassen in der Unterklasse dynamisch erstellen und an den Suite-Konstruktor übergeben. Dies ist jedoch eine unvollständige Lösung, da andere Unterklassen von Suite (z. B. Kategorien) nicht damit funktionieren und im Wesentlichen unterstützt keine dynamische Testklassensammlung.

Yishai
quelle
1
+1 dafür. Nachdem ich mich auf die Aufgabe gemacht hatte, eine dynamische Lösung für das Hinzufügen von Tests zu einer TestSuite zu schreiben, musste ich TestCase in jedem meiner Tests erweitern. Dies wiederum hat zuvor funktionierende Unit-Tests unterbrochen, bei denen JUnit4-Annotationen verwendet wurden, um erwartete Ausnahmen zu definieren. Meine Suche nach einer Möglichkeit, eine
Testsuite dynamisch
4

Sie sollten JUnit 4 verwenden. Es ist besser.

Viele Frameworks haben begonnen, die Unterstützung von JUnit 3.8 zu verwerfen.

Dies ist aus der Spring 3.0-Referenzdokumentation:

[Warnung] Die Legacy-Klassenhierarchie von JUnit 3.8 ist veraltet

Im Allgemeinen sollten Sie immer versuchen, die neueste stabile Version eines Frameworks zu verwenden, wenn Sie etwas Neues starten.

Espen
quelle
1
  1. Der "bevorzugte" Ansatz wäre die Verwendung von Anmerkungen, die seit dem 4. Juni eingeführt wurden. Sie erleichtern viele Dinge (siehe Ihre zweite Frage).

  2. Sie können dafür einen einfachen Try / Catch-Block verwenden:


public void testForException() {
    try {
        Integer.parseInt("just a string");
        fail("Exception should have been thrown");
    } catch (final Exception e) {
        // expected
    }
}
schwarz666
quelle