JUnit Einstieg - Verständnisfrage Download testen

OnDemand

Top Contributor
Hallo zusammen,

ich habe eine Methode, welche eine TXT Datei von einer URL herunterlädt, lokal speichert und aus dem Inhalt eine Map erstellt.

Die Testmethode prüft, ob die zurückgegebene Map size()>0 ist. Funktioniert auch. Aber irgendwie fühlt es sich falsch an, jedesmal die Datei herunterzuladen. Vor allem wenn Jenkins baut und die Tests durchläuft, dann dürfte der Download schief gehen weil die Pfade, wo die Datei hingespeichert wird, nicht vorhanden sind auf Jenkins.

Versteht jemand mein Problem und kann den Knoten lösen? Hab an anderen Stellen auch noch solche Downloader-Methoden, welche Bilder herunterladen.

Sollte ich die Download Methode zerpflücken und nur prüfen ob die URL korrekt gelesen wird und dann mit Testdaten die Map aufbauen und prüfen ob das Erstellen der Map funktioniert?
 

OnDemand

Top Contributor
Ah, das simuliert quasi die Gegenstelle. Das schaue ich mir dann mal an.
Nun hab ich Jenkins mal bauen lassen, ging natürlich nich. Da ich im Test @SpringBooTest drin habe. Da versucht es sich mit einer DB zu verbinden (die da auf dem Jenkins Server natürlich nicht liegt).

Was macht man da? H2 Datenbank und diese beim Hochfahren mit den wichtigsten Daten befüllen?
 

mrBrown

Super-Moderator
Mitarbeiter
Kommt generell ganz drauf an, was genau getestet werden soll.

Neben Mocks und H2 kann man auch einfach die echte Datenbank zB mit Test Containers starten, damit läuft der Test dann soweit möglich unter den echten Bedingungen.
 

OnDemand

Top Contributor
Kommt generell ganz drauf an, was genau getestet werden soll.

Neben Mocks und H2 kann man auch einfach die echte Datenbank zB mit Test Containers starten, damit läuft der Test dann soweit möglich unter den echten Bedingungen.
Hmmm dann könnte ich ja im prinzip meine lokale Datenbank auf den Server legen und da anbinden. Dann würde Jenkins beim Bauen auch da drauf zugreifen uns nicht meckern, dass er keine lokale H2 hat (da sind auch immer Testdaten drin)

Ganz schön umfangreich. Gleich erstmal ein Buch bestellt 😂

Testet man grundsätzliche jede Methode? Dann baut das ja irgendwann Stunden oder?
 

mrBrown

Super-Moderator
Mitarbeiter
Hmmm dann könnte ich ja im prinzip meine lokale Datenbank auf den Server legen und da anbinden. Dann würde Jenkins beim Bauen auch da drauf zugreifen uns nicht meckern, dass er keine lokale H2 hat (da sind auch immer Testdaten drin)
Je nachdem was du mit "lokale Datenbank auf den Server legen und da anbinden" meinst: aufpassen, dass (im Idealfall) jeder Build seine eigene, frische Datenbank hat. Nichts ist nerviger als fehlschlagende oder falsch-erfolgreich laufende Builds, weil die Datenbank grad "zufällig" im falschen/richtigen Zustand war.

Testet man grundsätzliche jede Methode? Dann baut das ja irgendwann Stunden oder?
implizit testet man, wenn man jede Funktionalität testet, auch jede Methode – zumindest im Idealfall, in der Realität machen das (leider) die wenigstens so.
 

OnDemand

Top Contributor
wenn ich also einen Testbuild mache welcher dann auf einen Test Server deployed wird und ich hab in der version die Datenbank erweitert, bleibt mir eigentlich nur die Möglichkeit mit H2.

Die Testdb ist ja dann noch in der alten Version und wird erst updated wenn der Testservice neu gestartet wird und flyway die dB updated.

Wenn Jenkins aber baut und die Methoden testet, welche neu dazugekommen sind (uns die neuen Tabellen brauchen) schlägt der Test fehl.

Dann kann ich mit h2 sicherstellen, dass sich das neuen .sql Script korrekt ist welches die DB updated, ohne dass eine physische DB falsch updated wird.

ich werd mal bei der h2 Variante bleiben mal sehen welche Probleme da noch so kommen 😜
 

sascha-sphw

Top Contributor
Damit das Problem, das @mrBrown beschrieben hat, nicht auftritt, hat sich bei den Tests das Arrange-Act-Assert Pattern etabliert.

Arrange: Alle Daten und Objekte werden für den Test vorbereitet. Also die DB in einen bestimmten Zustand gebracht, alle Abhängigkeiten gemockt oder erstellt, usw.
Act: Hier wird die Methode die getestet werden soll, mit den vorbereiteten Daten aufgerufen.
Assert: Testen ob das IST mit dem SOLL übereinstimmt.
 

OnDemand

Top Contributor
Hi, also h2 ist keine Lösung, da dir einiges nicht unterstützt was so eine richtige dB kann. Nun hab ich eigens für Jenkins eine Datenbank erstellt welche mir flyway initialisiert und updated wird. Bestimmte Parameter werden automatisch in Tabellen eingetragen wie defaultwerte, Einstellungen usw.

Folgende Überlegung:

mich lege unter Test jeweils 2 properties für spring an. Einmal wo lokale dB Verbindungen stehen zum entwickeln und eine für jenkins zum Bauen.
Heißt ich entwickle lokal auf einer lokalen dB, wenn jenkins baut hat es eine eigene dB für die Tests welche es über flyway updated usw. so werden die scrips auch nochmal auf Funktion „geprüft“
Macht das so halbwegs Sinn?
 

sascha-sphw

Top Contributor
Dafür gibt es in Spring Profile, Du kannst Dann z.B. einfach eine application-local.[properties|yml] in einen config Ordner im root Verzeichnis deines Projekts anlegen. Und über die IDE startest Du dann einfach das Profil local. Die Profile kannst Du nennen wie du möchtest. Die application.[properties|yml] bleibt da wo sie ist und ist Default, also ohne Angabe des Profils aktiv.
1622011338664.png
1622011401919.png
1622011466646.png
 

OnDemand

Top Contributor
Danke, ja so habe ich das auch gemeint und nutze ich auch so. Nur nicht in Verbindung mit JUnit :)
Meine eher ob das so Sinn macht mit der Datenbank lokal fürs Entwicklen, eine online für Jenkins.
 

thecain

Top Contributor
Macht das so halbwegs Sinn?
Nur halbwegs, jedenfalls so wie ich es verstanden habe.

Wird die Datenbank mit jedem Build komplett neu gebaut? Wirklich "sauber" ist es meiner Meinung nach erst, wenn du bei jedem Build genau die selbe Ausgangslage hast, also keine alten Daten mehr in der DB.

Das kann Beispielsweise mit einem Docker Container erreicht werden. Die meisten Tests sollten sowieso ohne DB funktionieren.
 

OnDemand

Top Contributor
ich würde die löschen und dann neu aufbauen lassen vor jedem build und mit den initialen Daten befüllen.

Docker würde doch im Prinzip nix anderes machen als ein MySql hochfahren oder?
 

OnDemand

Top Contributor
Hab es jetzt mit docker umgesetzt. Das ist ja perfekt! Vielen Dank für den Hinweis.

ne frage; wie viele Tests habt ihr so pro klasse und wie lange dauert dann ein Build 😅 fühlt sich an als würde so ein Build sich ums Zehnfache verlangsamen
 

sascha-sphw

Top Contributor
Ich habe welche die brauchen ca. 30x so lange als ohne Tests. Aber da bei mir der ganze Prozess voll automatisch läuft, ist es für mich nicht so wichtig wie lange das baut.

Edit: 30x ist eine Desktop Applikation, bei der ich mit Testfx und Monocle auch UI Tests mache.
 

mrBrown

Super-Moderator
Mitarbeiter
wie viele Tests habt ihr so pro klasse und wie lange dauert dann ein Build
Explizit Tests für konkrete Klassen? Zwischen 0 (wird dann aber durch andere Tests mitgetestet) und ein paar Duzend (grad wenn man parametrisierte Tests einzeln zählt) – das sind aber alles tests, die zusammen in wenigen Sekunden durchlaufen.

Länger dauernde Integrationstests/Systemtests/Whatever sind nie auf einzelne Klassen bezogen, sondern immer aufs Gesamtsystem, das sind zwischen ein paar Duzend und einigen Hundert. Die dauern durchaus zusammen einige Minuten, je nachdem was gemacht wird.

Im CI-Builds braucht das dann sowieso noch ein vielfaches der Zeit, weil das gegen mehrere Java-Versionen und u.U. auch verschiedene Dependencies getestet wird.
 

LimDul

Top Contributor
Man muss sich klarmachen, was will ich eigentlich wie und wo testen. Und tests, die eine Datenbank brauchen sind oft keine reinen Unit Tests mehr.

Aktuelle Zahl an Unit-Tests bei uns im Projekt ist momentan 5598. Ein maven clean test dauert auf dem Jenkins zwischen 6 und 11 Minuten, je nach dem wie viel CPU gerade zur Verfügung steht. Es sind da aber auch ein paar Testfälle bei, die man nicht mehr als Unit-Test formal zählen sollte, sondern die schon in die Richtung Integrationstest gehen.

Unit-Tests sollten Tests sein, die klein, gekapselt sind und sehr schnell durchlaufen. Sie sollen ja auch nur "eine Unit" testen. Davon sollte man so viele wie sinnvoll möglich haben. Tests, die z.B. eine Datenbank oder einen EJB-Context brauchen, sollte man eher spärlich einsetzen. Den die brauchen im Verhältnis oft extrem lange und sind ggf. auch wartungsintensiv.

Die Kunst und die Herausforderung ist, den Code so zu schreiben, dass man überhaupt solche Unit-Tests in der Masse erstellen kann und diese auch wartbar sind. Den nichts ist schlimmer als ein Unit-Test, der erst mal aus 50 Zeilen Mockito.mock und Mockito.when besteht. Da reicht dann oft eine Änderung an irgendeiner Komponetne und dieser Unit-Test geht auf die Bretter und keiner weiß so genau warum. Das ist ja einer der zentralen Vorteile von Test Driven Development. Wenn ich meine Tests zuerst schreibe, dann bekomme ich automatisch eine API die testbar ist. Schreibe ich erst meinen Code und dann die Tests ist das oft nicht der Fall und man muss entweder den Code refaktoren (wird ungerne gemacht, weil das Problem oft sich über mehrere Komponenten & Schichten zieht), auf Tests verzichten (wird gerne gemacht, insbesondere wenn die Zeit knapp ist) oder mit Mockito, Reflections oder Co doch noch irgendwie einen Test hinstellen (Der in der Aussagekraft begrenzt ist und sehr fragil gegen Änderungen ist) oder man baut eine komplette Umgebung mit Datenbank und Co auf (was mit entsprechenden Tooling oft geht, aber dafür die Laufzeit der Tests ins unendliche steigert, wenn man das zu oft macht)
 

OnDemand

Top Contributor
Wow doch nicht so lange wie gedacht :p
Habe jetzt mal ein Paar Test-Tests geschrieben. zb menie Spring Services testen ob die Methoden zum speichern und holen von Entites funktionieren oder eine Methode, welche Verkaufspreise berechnet - ob sie den korrekten Wert ausgibt.
Das sind Unit Tests, richtig?
Mehr brauch ich eigentlich erstmal nicht, ich möchte nur verhindern, dass ich neue Features oder Änderungen mit dem Arsch nicht irgendwo was einreisse, was vorher funktioniert hat.
 

Neue Themen


Oben