Dies ist eine Einführung in die Unterschiede bezüglich der Features, der Assert-Befehle ("assertFalse", "assertEquals", etc.) und der Annotationen ("@BeforeEach", etc.) der beiden populären Testframeworks "JUnit" und "TestNg".
Die Entscheidung für das geeignete Test-Framework ist wichtig, um die Qualität Ihrer Software sicherzustellen. Das beste Test-Framework kann sich hinsichtlich der Größe und Art Ihrer Software und deren Abhängigkeiten unterscheiden.
In diesem Tutorial kommen die JUnit Version 5 und TestNG Version 7 zum Einsatz.
Funktionalität
Beide Frameworks verfügen über parametrisierte Tests, Timeout-Funktion und Ausnahmetests. Aber TestNG hat einige fortgeschrittenere Funktionen, und es ist auch möglich, mehr als Unit-Tests durchzuführen.
Diese beiden Test-Frameworks unterscheiden sich in den folgenden Merkmalen und Funktionen:
JUnit
- Standardmäßig in Ihrer IDE installiert
- Konfiguration erfolgt nur von Java-Testklassen aus
- Keine Notwendigkeit für eine zusätzliche XML-Konfigurationsdatei
- Größere Gemeinschaft
- Mehr Dokumentation.
- Angepasst für Unit-Tests.
TestNG
- Testsuite wird über die Datei testng.xml konfiguriert
- Erstellen Sie Gruppen von Tests, die zu verschiedenen Klassen gehören, über die Datei "testng.xml".
- Abhängigkeitstests (Befehl: "dependsOnMethod")
- Parallele Testausführung (Attribut in der XML-Datei "testng": "parallel")
- Konfigurieren Sie die Reihenfolge, in der die Testfälle ausgeführt werden (Befehl: "priority")
- HTML-Bericht wird standardmäßig erstellt
TestNG organisiert Ihren Unit-Test ein wenig anders als JUnit. Alle Testfälle, die Sie erstellt haben, gehören immer zu einer Testsuite, die in der XML-Datei "testng" definiert sind.
Ein Beispiel für die XML-Datei "testng":
<suite name = "MySuite">
<test name = "testAddObject">
<classes>
<class name = "Test1" />
</classes>
</test>
<test name = "testDeleteObject">
<classes>
<class name = "Test2" />
</classes>
</test>
</suite>
Assertions
Diese beiden Frameworks haben die gleichen Assertion-Methoden ("assertEquals", "assertFalse", "assertAll", "assertThrows" usw.). Sie unterscheiden sich jedoch in der Reihenfolge der Methodenargumente, die wie folgt aussehen:
AssertEquals
"assertEquals" ist für alle Datentypen verfügbar. Es prüft, ob die übergebenen Objektwerte gleich sind. Diese Methode verwendet "equals()", um die beiden übergebenen Objekte zu vergleichen.
JUnit:
assertEquals(Object expected, Object actual, String message)
TestNG:
assertEquals(Object actual, Object expected, String message)
Dieser Unterschied ist bei allen anderen Behauptungen derselbe. Beispiel: "assertTrue", "assertSame", etc.
Dies sind die Behauptungen, die für ein bestimmtes Test-Framework spezifisch sind:
AssertTimeout
Diese Assertion prüft, ob die Ausführungszeit den definierten Zeitwert ("timeout") nicht überschritten hat.
JUnit:
assertTimeout(Duration timeout, Executable executable)
Sie müssen die maximale Zeit (als "Duration"-Objekt) übergeben, die die Funktion im zweiten Argument in Anspruch nehmen soll. Beispiel:
@Test
public void testMultiplicationDuration() {
assertTimeout(Duration.ofSeconds(5), calculation.multiplication(545455, 2545455));
}
TestNG:
Dafür gibt es keine Assertion. Aber Sie können dasselbe tun, indem Sie den Befehl "timeout" zur Anmerkung "@Test" hinzufügen. Die Zeit wird in Millisekunden angegeben.
@Test(timeOut = 5000)
public void testCalculation() throws InterruptedException {
Assert.assertEquals(calculation.multiplication(545455, 2545455), 1388431157025);
}
assertEqualsDeep
Dies ist nur in TestNG verfügbar. Hier werden die Elemente einer "Map" oder eines "Set" verglichen.
assertEqualsDeep(java.util.Map<?,?> actual, java.util.Map<?,?> expected, java.lang.String message)
assertEqualsDeep(java.util.Set<?> actual, java.util.Set<?> expected, java.lang.String message)
Wenn Sie dies in JUnit tun wollen, dann können Sie es direkt mit "assertTrue" wie folgt tun:
assertTrue(expectedMap.equals(actualMap));
Annotations
Beide Frameworks haben fast die gleiche Art von Annotationen. Sie unterscheiden sich meist in ihrer Bezeichnung.
@BeforeEach - @AfterEach
In TestNG werden diese Anmerkungen "@BeforeMethod" und "@AfterMethod" genannt. Damit wird eine Methode jedes Mal vor oder nach einer Testmethode ausgeführt (Methoden mit der Anmerkung "@Test", "@RepeatedTest", "@ParameterizedTest" oder "@TestFactory").
Es gibt auch Annotationen, die in JUnit nicht verfügbar sind, wie z.B. "@DataProvider".
@RepeatedTest
Dies ist nur in JUnit verfügbar und wiederholt eine Testmethode eine bestimmte Anzahl von Malen. Beispiel:
@RepeatedTest(10)
public void test10Times() {
System.out.println("Repeated test - Run 10 times");
}
In TestNG können Sie dies auf eine andere Art und Weise tun:
@Test(invocationCount = 10)
public void test10Times() {
System.out.println("Repeated test - Run 10 times");
}
@DataProvider
Ein "DataProvider" ermöglicht das Übergeben von parametrisierten Daten an die Argumente einer Test-Methode.
Doest steht in testNG zur Verfügung und ist in JUnit standardmäßig nicht verfügbar. Wenn Sie eine Art von "DataProvider" in JUnit verwenden möchten, dann müssen Sie die Abhängigkeit "JUnit DataProvider" zu Ihrem Projekt hinzufügen.
Die Daten, die Sie an Ihre Methode übergeben möchten, werden in einer separaten Methode erstellt (mit der Annotation"@DataProvider"), die Ihr "DataProvider" sein wird und Ihre erstellten Daten als ein Objekt-Array zurückgibt.
Sie können dann Ihre erstellten Daten über Ihre Methodenargumente übergeben, indem Sie das Annotationsattribut "dataProvider" verwenden.
Beispiel:
@DataProvider
public Object[][] getTenCostCategoryItems() {
Object[][] costCategoryItems = new Object[][]{{"Tire Change", 2000, 1}, {"Paint Color", 6000, 2}, {"Repair Engine", 8000, 3}, {"Repair Windshield", 7000, 4}, {"Change Entertainment System", 4600, 5}, {"Repair Audio Boxes", 8000, 6}, {"Change Seating", 7600, 7}, {"Change Oil", 9000, 8}, {"Repair Door", 8000, 9}, {"Change Lights", 4000, 10}};
return costCategoryItems;
}
@Test(dataProvider = "getTenCostCategoryItems")
public void testAddTenAndCheck(String costCategoryItemTitle, Integer costCategoryItemPriceCent, Integer index) {
CostCategory expectedCostCategoryItem = new CostCategory(costCategoryItemTitle, costCategoryItemPriceCent);
this.costCategoryService.add(expectedCostCategoryItem);
CostCategory actualCostCategoryItem = this.costCategoryService.getById(index, classObject);
try {
assertEquals(actualCostCategoryItem.getTitle(), expectedCostCategoryItem.getTitle(), "Added title should be saved in database.");
assertEquals(actualCostCategoryItem.getCentPrice(), expectedCostCategoryItem.getCentPrice(), "Added CentPrice should be saved in database.");
assertEquals(actualCostCategoryItem.getId(), index, "PK must be " + index + ".");
} catch (NullPointerException e) {
fail("Created object was not saved in database");
}
}
In diesem Beispiel erhält die Testmethode "testAddTenAndCheck" zehnmal einen String "costCategoryItemTitle", einen Integer "costCategoryItemPriceCent" und einen Integer "index" aus dem Array "costCategoryItems". Diese Werte dieser Variablen sind über die Argumente dieser Testmethode verfügbar.
Dies war eine Einführung in die Unterschiede zwischen JUnit und TestNG. Es gibt auch einige andere Assertions und Annotations. Weitere Informationen finden Sie in der Dokumentation.
Abhängigkeit "JUnit DataProvider":
https://mvnrepository.com/artifact/com.tngtech.java/junit-dataprovider
TestNG Dokumentation:
https://www.javadoc.io/doc/org.testng/testng/7.0.0/org/testng/Assert.html
JUnit Dokumentation:
https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html