Wir freuen uns ein neues Open Source Projekt vorstellen zu können: Testcontainers Infrastructure (TCI) Framework
Dieses Framework basiert auf Testcontainers und stellt folgende Kernfunktionen bereit:
1. Verbesserte Anpassbarkeit und Parallelisierung
Durch die Verwendung des Factory Patterns bei der Erstellung von Container wird es für den Entwickler einfacher die Container nach Bedarf anzupassen:
Ohne TCI | Mit TCI |
|
|
Für jede “Infrastruktur” (Abgekürzt: TCI) gibt es eine Factory um eine neue TCI zu erstellen. Diese Factory kann leicht konfiguriert werden und kümmert sich um Dinge wie die Erstellung von Containern, PreStarting und die Verfolgung der gestarteten TCI für die weiter unten genannten Features.
Container/Infrastruktur kann wie folgt in einer TCI_FACTORY-Klasse angepasst werden:
@Override
public void start(final String containerName) {
super.start(containerName);
if(doMigrate) {
this.migrateDatabase(BASELINE_FOR_TESTS);
}
}
void migrateDatabase(String version) {
// Datenbank mithilfe von z.B. Flyway migrieren
}
Dies bedeutet, dass es nun möglich ist, zusätzlichen, nicht containerbezogenen Code hinzuzufügen, wie z.B. Clients oder allgemeine Methoden (z.B. createUser), ohne den Container selbst zu verändern. Dies folgt dem composition over inheritance Designprinizip.
Durch den Einsatz von Factories kann das Framework auch die Leistung mittels Parallelisierung und PreStarting verbessern.
2. Test so schnell wie möglich ausführen
Warum ist das überhaupt wichtig?
Die schnellstmögliche Ausführung von Tests hat mehrere Vorteile:
- Bei Lokeler Ausführung:
In der Regel gibt es nichts anderes zu tun, wenn man Tests lokal durchführt - außer vielleicht einen Kaffee zu trinken. Es ist auch möglich, eine andere Aufgabe zu beginnen, aber dann verliert man vielleicht den Fokus auf die ursprüngliche Aufgabe und muss sich später wieder in das Thema einarbeiten.
- Bei Benutzung einer CI:
- Wenn man für Rechenleistung bei Bedarf bezahlt (z. B. minutenbasierte Abrechnung von Spot-Instances) kann die schnellere Durchführung von Tests (ohne Vergrößerung des verwendeten Rechners) aufgrund der geringeren Mietdauer viel Geld sparen.
- Wenn man für eine feste Menge an Rechenleistung bezahlt, bedeutet eine schnellere Ausführung von Tests, dass mehr Zeit für andere Aufgaben zur Verfügung steht, die auf der CI ausgeführt werden können.
Wenn die Zeitersparnis groß genug ist, kann man auch über eine Verringerung der erforderlichen Rechenleistung nachdenken.
- Schnelleres Test-Feedback: Wenn z.B. vor einem Release alle Integrationstests erfolgreich ausgeführt werden müssen, kann dies die Zeit für die Auslieferung des Releases verkürzen.
- Wenn man für Rechenleistung bei Bedarf bezahlt (z. B. minutenbasierte Abrechnung von Spot-Instances) kann die schnellere Durchführung von Tests (ohne Vergrößerung des verwendeten Rechners) aufgrund der geringeren Mietdauer viel Geld sparen.
Das Framework ist explizit auf Parallelisierung ausgelegt und bietet mehrere Funktionen zur Beschleunigung von Tests:
2.1. PreStarting Mechanismus
Bei der Durchführung von Tests gibt es in der Regel bestimmte Zeiten, in denen die verfügbaren Ressourcen kaum ausgelastet sind:
PreStarting verwendet einen gecachten Pool von Infrastrukturen und versucht, diese Leerlaufzeiten zu nutzen, um diesen Pool aufzufüllen. Wenn eine neue Infrastruktur angefordert wird, muss nicht auf ihre Erstellung gewartet werden, sondern es kann die bereits gestartete Infrastruktur aus diesem Pool verwendet werden - sofern sie verfügbar ist.
Performance-Boost
Wenn PreStarting korrekt implementiert wurde kann dies einen enormen Leistungsunterschied bewirken, wie in unserem Leistungsvergleich zu sehen ist
Des Weiteren gibt es auch ein Live-Beispiel (mit GitHub Actions), das die folgenden Ergebnisse liefert:
Fall | Parallelisierung | PreStarting aktiv? | Benötigte Zeit um alle Tests auszuführen |
---|---|---|---|
A | - | ❌ | 8m 50s |
B | - | ✔ | 5m 30s |
C | 2 | ❌ | 6m |
D | 2 | ✔ | 4m 50s |
Wie wir sehen können, gibt es im besten Fall (D) eine Geschwindigkeitsverbesserung von fast 50 % im Vergleich zur Durchführung der Tests auf herkömmliche Weise (A).
2.2. Optimierte Testcontainers Netzwerke
Es wird eine optimierte Implementierung von Testcontainers Network verwendet:
Vorher | Nachher |
NetworkImpl code aus Testcontainers 1.20
| LazyNetworkPool bietet einen Pool von Netzwerken, die im Hintergrund erstellt werden. Es geht keine Zeit mit dem Warten auf die Netzwerkerstellung verloren. |
2.3. Container Leck Erkennung
Erkennt ob gestartete Container/Infrastruktur auch beendet wurden und verhindert dadurch, dass es zur Ressourcenerschöpfung kommt.
Im folgenden Beispiel wird der Testcontainer zwar erstellt, aber nie beendet.
@Test
void test() {
DummyTCI tci = DUMMY_FACTORY.getNew(...);
...
}
Nachdem die Tests mit dem Framework ausgeführt wurden, erscheint folgende Fehlermeldung:
ERROR s.x.tci.leakdetection.TCILeakAgent - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR s.x.tci.leakdetection.TCILeakAgent - ! PANIC: DETECTED CONTAINER INFRASTRUCTURE LEAK !
ERROR s.x.tci.leakdetection.TCILeakAgent - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ERROR s.x.tci.leakdetection.TCILeakAgent - All test are finished but some infrastructure is still marked as in use:
DummyTCIFactory leaked 1x [container-ids=[c1b6be852fac3bf65ac8f2739ab161d7f95bc4c62699c698ccc8b74da1be8a3d]]
3. Quality of Life Verbesserungen
Das Framework enthält auch einige kleinere Verbesserungen:
3.1. Container-Namen die ein Mensch lesen kann
Alle gestarteten Container haben einen eindeutigen, von Menschen lesbaren Namen. was die Identifizierung erleichtert.
Vorher | Nachher |
|
|
3.2. Statistiken zur Testlaufzeit
Ein Nachverfolgungsmechanismus, der das Auffinden von Engpässen und ähnlichen Problemen erleichtert
Beispiel:
[main] [i.tracing.TCITracingAgent] === Test Tracing Info ===
Duration: 2m 43.608s
Tests: 20.656s / 15 / 5m 9.84s
BrowserTCIFactory-firefox:
bootNew - 1ms / 6 / 5ms
connectToNetwork - 515ms / 5 / 2.575s
getNew - 574ms / 5 / 2.87s
infraStart(async) - 14.575s / 6 / 1m 27.448s
postProcessNew - 54ms / 5 / 270ms
warmUp - 2.448s / 1 / 2.448s
...
Weitere Informationen
Das Framework ist auf GitHub verfügbar. Details zu Benutzung findet man unter “Usage”. Es sind auch mehrere Demos verfügbar.
Bei weitere Fragen oder falls Hilfe benötigt wird, kann man ein Issue erstellen oder unseren Support kontaktieren.
Und nicht vergessen: Gerne kann man dem Repo auch einen Stern 🌟 geben.