Tools für End-to-End-Tests

Meine Anwendung läuft ebenfalls in einem Container, sodass das Problem nicht präsent ist.

Dass zufällige Ports nicht zuverlässig sind, war mir nicht bekannt. Wie äußert sich das? Scheitert dann der Anwendungsstart?

Direkt die offizielle Java-Bibliothek zur Kommunikation mit dem Docker-Daemon zu nutzen, ist wahrscheinlich ziemlich aufwändig und daher uninteressant.

Dass das Setup in die Tests gehört, sehe ich auch so. Der Build sollte nur als Trigger für den Testcode dienen. Dein Ansatz gefällt mir sehr gut!

Über welche Größenordnung von Zeit reden wir hier? Du solltest die IT’s und E2E eben so machen, dass die Bereiche Testen, die man über Unit Tests faktisch nicht testen kann. Und E2E eben machen, was über IT’s faktisch nicht testbar ist…

Somit sehr wenige E2E’s, mehr IT’s und noch mehr Unit Tests… (Klassischer Ansatz der Test Pyramide)…

Gruß
Karl Heinz

Dass zufällige Ports nicht zuverlässig sind, war mir nicht bekannt. Wie äußert sich das? Scheitert dann der Anwendungsstart?

Klassische Meldung eben… „…port already in use…“ … genau die Anwendung startet dann eben nicht…

Ich hab gerade das Video parallel laufen und daher jetzt auch gesehen, was du mit dem SocketUtils-Ansatz meinst. Ich ging davon aus, dass du mit zufälligen Ports vom Servlet-Container vergebene Ports meintest. Wenn der Servlet-Container den Port vergibt, muss man natürlich das Problem lösen, den ausgewählten Port zu identifizieren. Da gibt es mehrere Möglichkeiten, unter anderem könnte man von dem gestarteten Prozess die lauschenden Ports auflisten lassen oder man lässt die Anwendung den Port „irgendwo hinschreiben“.

Dass es nur sehr wenige Szenarien, die „richtig E2E“ sind, gibt, schrieb ich oben ja schon. Von daher sind Startzeiten von 1 Minute und mehr wohl auch verschmerzbar.

Nein. Wir hatten ganz zu Anfang mal wirklich per Random Ports ausgesucht und dann per CLI an Spring übergeben…aber bei 10-20 Branches Parallel fällt das schon mal auf die Nase… (vollkommen klar…)

Und bei Laufzeiten für die E2E’s von mehreren Stunden …ist das schon etwas ärgerlich…

SocketUtils funktioniert deutlich besser aber auch nicht 100%ig…

Startzeit der Anwendung ist hier nicht das Problem ca. 30 Sekunden / DB Container Startzeit ca. 30 Sekunden… die Laufzeit ist schlicht der Knackpunkt…Aber das Ganze hat uns schon so viel geholfen…

Glaube ich dir gern. Danke nochmal für das Aufweisen dieses Ansatzes. Dort steckt sehr viel Potenzial und er ist sehr flexibel. Praxiserfahrung fehlt mir diesbezüglich natürlich noch, aber ich denke, dass ich das auf jeden Fall auf meine Anwendungsfälle zuschneiden kann.

1 „Gefällt mir“

Sieh dir mal https://cucumber.io an, da kann man schöne high level Tests schreiben die sehr lesbar sind.

Mit dem Maven Failsafe Plugin (auch mit surefire) kann man Listen von tests übergeben die ausgeführt werden sollten, da hab ich schon mal die Tests über mehrere Maschinen aufgeteilt die dann Parallel ihren Chunk der Testsuite abarbeiten, der Trick war dass diese einzelnen Chunks mehr oder weniger ähnliche Laufzeiten hatten, dafür gab es eine Datei die alle Laufzeiten aller tests enthielt, die einzelnen Chunks waren „fest“ (getrackt in Git) bis diese explizit geändert wurden, damit die Reihenfolge sich nicht ständig ändert.

@kama gut wieder was von dir hier zu lesen :slight_smile:

1 „Gefällt mir“

Von cucumber habe ich schonmal gehört, es mir aber noch nicht genauer angesehen. Klingt wie ein brauchbares Werkzeug, das in den Test-Tools-Werkzeugkasten passen könnte. Ein bisschen uncool ist, dass cucumber noch auf JUnit 4 basiert. Das beißt sich dann mit @kama s Ansatz für die Test-Fixture.

Das ist jetzt schon halb off-topic, weil es sich nicht nur auf End-to-End bezieht, aber: was habt ihr sonst noch so für Tools? Mein derzeitiges Toolset besteht aus JUnit 5, mockito(-inline seit Java 17, wegen records), assertj, spring-test, awaitility, okhttp mockserver und, wenn man es noch dazu zählen möchte, threeten-extra. Vielleicht hab ich noch ein kleineres Helferlein vergessen, aber im groben sollte es das sein.

Das mit JUnit 4 ist genau das Problem warum ich bisher ausschlieslich mit JUnit Jupiter fahre…

Und ich muss zugeben, dass ich den Vorteil von Cucumber bisher anscheinend noch nicht verstanden habe… In Ruby fand ich das recht einfach wg. dem dynamischen Ansatz (und recht gut)…aber in Java …werde ich bisher nicht „warm“ damit. Alternative https://jgiven.org/ (Leider JUnit Jupiter noch experimental)…

JUnit Jupiter, Mockito, AssertJ, manchmal auch Hamcrest, Equalsverifier, Testcontainers, https://www.xmlunit.org, memoryfilesystem, an manchen Stellen Byte-buddy, awaitility…im Java Umfeld…

Klar dann kommt noch der Bereich aus Frameworks wie z.B. Spring Boot (Spring test etc.) dazu…

Dann noch so Tools wie JaCoCo, PITest

Habe mal vor längerer Zeit https://jmockit.github.io/ genutzt…, TestNG habe ich auch lange Zeit genutzt (vor JUnit Jupiter)…

Google Truth wäre auch noch eine Möglichkeit https://truth.dev/ aber bisher bei AssertJ hängen geblieben…

Gruß
Karl Heinz

Ich nutze gerne Testcontainers - gerade bei System-Integrationstests (oder hier Ende-zu-Ende). In Memory-DBs verhalten sich häufig anders (z.B. H2 vs PostgreSQL).

Spring Boot, Junit5 und Testcontainers laufen sehr stabil miteinander.

Ein Beispiel: spring-boot-demos/TweetControllerIT.kt at main · larmic/spring-boot-demos · GitHub

wie macht ihr das eigentlich mit der DB ist der Container komplett fertig vorbereitet oder gibts nen Script was beim Start die Daten in die DB prügelt?

Also wir nutzen flyway. Auch um das Schema zu erstellen. Da es sich um Integrationstests handelt, passt das zeitlich für unser Team.
Ansonsten befüllen wir die Datenbank mit Testdaten ganz normal, indem wir entities befüllen und über die repositories und die Datenbank speichern.

Über den Build oder die Test-Fixture getriggert?

Wenn die DB in einem Container lebt, der direkt erzeugt wird, wohl in der Test-Fixture, oder?

Wir nutzen die SpringBoot-Annotation @ContextConfiguration, um vor dem Test die DB zu starten. Die Daten kommen dann meist über ein Fixture in die DB.