JUnitTest Best Practise (Ein Assert pro Test?)

PinkMuffin

Bekanntes Mitglied
Hallo, ich hab nicht wirklich ein Code-Problem, mittlerweile funktioniert alles, allerdings sind Teile des Codes noch etwas unübersichtlich gewesen, deshalb hab ich mir die Best-Practices zu Java und JUnit mal angeguckt.
An vielen Stellen heißt es, dass in JUnit bestenfalls nur ein Assert pro Testfunktion vorhanden sein soll.
Allerdings kann ich mir nicht so recht vorstellen, dass das der Übersicht dienen würde.
(Eine der zu testenden Methoden hängt von zwei Parametern ab, für die es eigentlich nur zwei relevante Ausgänge gibt, allerdings sollen wir laut unserem Prof insbesondere die Grenzfälle testen). Sollte ich diese Test-Methode weiter aufsplitten, oder kann ich das schöner schreiben/bzw zusammenfassen, weil ja alle Fälle mit dem gleichen Wert verglichen werden?

Java:
@Test
public void berechneBruttoPreis_nichtermaessigtUnd2020_Test()
{
    //act
    double preis1 = produktNichtermaessigt.berechneBruttopreis(untereGrenze);
    double preis2 = produktNichtermaessigt.berechneBruttopreis(obereGrenze);
    double preis3 = produktNichtermaessigt.berechneBruttopreis(mittenDrin);
   
    //assert
    assertEquals(2.9, preis1, 0);
    assertEquals(2.9, preis2, 0);
    assertEquals(2.9, preis3, 0);
}

Soll ich diese Fälle jetzt alle aufsplitten, oder wäre das übertrieben? Das würden ja auch unendlich lange Methodennamen werden, wenn ich die so benennen will, wie das an vielen Stellen angegeben ist, da die Parameter ja in großen Teilen identisch sind.

Danke schonmal ^^

EDIT: Voraussetzung wäre noch, dass es in JUnit 4 funktioniert
 
Zuletzt bearbeitet:

PinkMuffin

Bekanntes Mitglied
Stichwort: "Parametrisierte Tests"
Geht mit JUnit 4/5 und TestNG.
Du kannst eine Testmethode so deklarieren, dass sie alle möglichen Kombinationen an Werten als Parameter bekommt und dann hast du auch nur ein assert().
Danke, hätte vielleicht erwähnen sollen, dass wir JUnit4 verwenden müssen. Da hatte ich an verschiedenen Stellen (hier zum Beispiel https://www.testwithspring.com/lesson/writing-parameterized-tests-with-junit-4/) gelesen, dass es nicht häufig gemacht wird, weil es den Code nur noch unübersichtlicher macht, was ja das Gegenteil von dem wäre, was ich möchte..
 

httpdigest

Top Contributor
Ich glaube, die Art des Threads ist mit "Frage" hier dann falsch. Du stellst ja keine Frage, zu der es eine verifizierbar richtige Antwort gibt, sondern willst eine Diskussion, da das, was man als "besser", "leichter verständlich" bzw. "übersichtlich" versteht, von jedem selbst abhängt bzw. völlig subjektiv ist. Meine Meinung: Nutze einfach parametrisierte Tests, da dieser Mechsnismus genau dafür gemacht wurden. Plus: Es gibt hierfür gute Integration in IDEs, die dir z.B. die einzelnen Fälle auch als separate "Zeilen" anzeigen und dir die eventuell fehlschlagenden Wertekonstellationen auch hervorheben.
 

mrBrown

Super-Moderator
Mitarbeiter
Das Problem mit den mehreren Assertions in dem Fall ist, dass der Test immer mit einem "X ist nicht gleich Y" fehlschlägt, ohne Information darüber, was eigentlich schief gegangen ist. Das Ergebnis ist also völlig identisch, unabhängig davon, ob die gesamte Funktion falsch its, oder nur der obere oder untere Grenzwert falsch betrachtet werden.

Wenn du das aufteilst, bekommst du deutlich besser mitgeteilt, wo genau der Fehler liegt.


Danke, hätte vielleicht erwähnen sollen, dass wir JUnit4 verwenden müssen. Da hatte ich an verschiedenen Stellen (hier zum Beispiel https://www.testwithspring.com/lesson/writing-parameterized-tests-with-junit-4/) gelesen, dass es nicht häufig gemacht wird, weil es den Code nur noch unübersichtlicher macht, was ja das Gegenteil von dem wäre, was ich möchte..
Mit Junit 5 geht das zwar deutlich schöner als mit Junit 4, aber solche Tests wie du sie hast werden auch unter Junit 4 mit parametrisierten Tests übersichtlicher :)
 

LimDul

Top Contributor
Ich persönlich bin der Ansicht:

Ein Aspekt pro Testmethode. Das ist oft - aber nicht immer - ein assert. Es können manchmal auch mehrere Asserts sein. Z.b. Wenn ich testen will das ein Jahresbeitrag korrekt aufgeteilt wird bzgl. der fiskalischen Rechenregeln, dann hab ich automatisch zwei asserts - die die beiden aufgeteilten Werte testen

Für dein Beispiel würde ich tatsächlich 3 Methoden machen:
Java:
public void testBerechneBruttoPreis_nichtermaessigt2020UntereGrenze();
public void testBerechneBruttoPreis_nichtermaessigt2020MittenDrin();
public void testBerechneBruttoPreis_nichtermaessigt2020ObereGrenze();

Grundsätzlich sollte man aber test an den Afang der Methode schreiben. Und ja, das werden teilweise viele Methoden. Aber dafür hat man - wie @mrBrown sagt - im Fehlerfall auch direkt mehr Informationen und die Tests sind auch einfacher zu verstehen. Grundsätzlich bietet ja Junit an der Stelle auch Mittel den Overhead zu vermeiden. Eins wurde schon genannt, Parametrisierte Tests, man kann grundsätzlich auch in Tests gemeinsamen Code auslagen (in die entsprechenden setUp Methoden) und mit JUnit 5 kommen auch so Sachen wie NestedTests hinzu.

Aber das ich hier im Projekt von eine zu testende Methode teilweise 3 oder mehr Test-Methoden habe ist keine Ausnahme, sondern eher der Standardfall. In seltenen Konstellationen werden aus auch mal über 10 Methoden:

1609860495784.png
 

mrBrown

Super-Moderator
Mitarbeiter
BTW:
An vielen Stellen heißt es, dass in JUnit bestenfalls nur ein Assert pro Testfunktion vorhanden sein soll.
Das steht zwar an vielen Stellen so (und ich formulier es meistens auch so...), aber gemeint ist meist eher ein "Ein Test sollte eine Sache testen". Ob dafür genau eine Assertion oder mehrere nötig sind, ist dann eher zweitranging (vor allem auch, da je nach Assertion-Bibliothek sich die selbe Sache durch eine oder durch Fünf Assertions ausdrücken lässt, je nachdem wie mächtig das ist).
 

thecain

Top Contributor
Mit Junit 5 gibt es dann zusätzlich assertAll. Das hat den Vorteil, dass es beim ersten fehlgeschlagenen Assert nicht abbricht.
(Trotzdem sollte auch mMn nur ein Aspekt pro Test getestet werde.)

Bei JUnit 4 gab es das meines Wissens noch nicht.
 

mihe7

Top Contributor
Da kann ich mich meinen Vorschreibern nur anschließen: ein Aspekt pro Test - und getestet werden Funktionalitäten und keine Methoden. Dein "_Test()" ist doppelt gemoppelt, schließlich hast Du schon eine @Test-Annotation.

Doppelten Code kannst Du weiterhin durch Methoden verhindern. Und soll das Epsilon wirklich 0 sein?!?
 

PinkMuffin

Bekanntes Mitglied
Da kann ich mich meinen Vorschreibern nur anschließen: ein Aspekt pro Test - und getestet werden Funktionalitäten und keine Methoden. Dein "_Test()" ist doppelt gemoppelt, schließlich hast Du schon eine @Test-Annotation.

Doppelten Code kannst Du weiterhin durch Methoden verhindern. Und soll das Epsilon wirklich 0 sein?!?
Okay, klingt logisch, danke für die vielen Antworten.
Dann lagere ich das mal noch aus und lösche die Test-Bezeichnung. In vielen englischen Foren war das als Standard angegeben, aber du hast ja Recht, eigentlich ist es ja logisch, dass das eine Test-Methode ist.
Und der Spielraum soll 0 sein, da wir in der Aufgabe runden sollen, dürfte das auch eigentlich nicht zu Problemen führen.
 

LimDul

Top Contributor
Wir benennen im Projekt die Test-Methoden immer nach dem Schema

test<NameDerZuTestendenMethode>_<GetesteterAspekt>

Wobei GetesteterAspekt immer eine Gradwanderung zwischen Möglichst Kurz und Möglichst Aussagekräftig ist.
 

Ähnliche Java Themen

Neue Themen


Oben