Entwicklung & Code
Integration-Tests mit TestContainers: Von der Theorie zur Praxis
Wer Integration-Tests schreibt, kennt das Problem: Entweder man arbeitet mit Mocks, die nur begrenzt die Realität abbilden, oder man kämpft mit langsamen, schwer wartbaren Testumgebungen. Mocks haben den Charme, dass Tests schnell durchlaufen und keine externe Infrastruktur benötigen. Doch sie bergen eine Gefahr: Die Tests werden grün, weil die Mocks perfekt zu den Tests passen. Das heißt nicht unbedingt, dass der Code mit echten Systemen funktioniert. Wer garantiert, dass der Mock das Verhalten einer PostgreSQL-Datenbank oder einer Kafka-Queue korrekt abbildet?
Weiterlesen nach der Anzeige
Die Alternative in Form einer dedizierten Testumgebung mit echten Diensten bringt andere Probleme mit sich: Wie setzt man den Zustand zwischen Tests zurück? Wie verhindert man, dass Tests sich gegenseitig beeinflussen? Und wie stellt man sicher, dass die Testumgebung exakt der Produktionsumgebung entspricht?
Mit TestContainers gibt es einen pragmatischen Ausweg: Die Bibliothek startet echte Dienste in wegwerfbaren Docker-Containern. Jeder Test bekommt seine eigene, frische Instanz – komplett isoliert, mit definiertem Startzustand – und nach Testende automatisch aufgeräumt. Der Ansatz ist allerdings nur dann praktikabel, wenn die containerisierten Dienste schnell genug starten. Bei einer Datenbank, die in weniger als einer Sekunde bereit ist, lässt sich für jeden einzelnen Test ein neuer Container hochfahren. Bei Diensten mit mehreren Minuten Startzeit muss man hingegen zu Shared Containers greifen.
Die Idee hinter TestContainers
TestContainers ist ein Projekt zur programmatischen Steuerung von Docker-Containern in Tests. Der Kerngedanke ist simpel: Statt Mocks zu schreiben oder manuelle Testumgebungen zu pflegen, lässt man den Test selbst die benötigte Infrastruktur hochfahren. Nach Testende räumt TestContainers automatisch auf – kein manuelles Stoppen von Containern, keine vergessenen Ressourcen.
Die konzeptionelle Funktionsweise ist schnell erklärt: Ein Test startet einen oder mehrere Container, wartet, bis sie bereit sind, führt die eigentlichen Testschritte durch und stoppt zum Schluss die Container. TestContainers übernimmt dabei die dynamische Portzuordnung, sodass der Test sich nicht um Portkonflikte kümmern muss. Ein integrierter Reaper-Mechanismus sorgt dafür, dass Container auch dann aufgeräumt werden, wenn ein Test abstürzt oder abbricht.
Besonders wichtig sind die Wait Strategies. Ein gestarteter Container ist nämlich nicht automatisch sofort bereit, Anfragen zu verarbeiten. Eine Datenbank braucht beispielsweise Zeit zum Initialisieren, ein Webserver muss zunächst hochfahren. Wait Strategies definieren, wann ein Container als bereit gilt – etwa wenn ein bestimmter Port lauscht, eine HTTP-Anfrage erfolgreich ist oder eine spezifische Logzeile erscheint.
Weiterlesen nach der Anzeige
TestContainers bietet dabei bereits für viele gängige Anwendungen und Dienste vorgefertigte Module wie PostgreSQL, MySQL, Redis, MongoDB und Kafka. Diese Module sind Wrapper-Klassen um die generische Container-API, die bereits sinnvolle Defaults mitbringen, etwa Standardports, typische Umgebungsvariablen und passende Wait Strategies.
Für weniger verbreitete Dienste oder eigene Systeme kann man eigene Wrapper schreiben. Sie bauen auf dem GenericContainer auf und kapseln domänenspezifische Konfiguration. Das praktische Beispiel im Folgenden zeigt, wie unkompliziert die Umsetzung ist: eine Klasse, die das Image, Ports und Kommandozeilenparameter konfiguriert und eine Client-Instanz zurückgibt. Der Wrapper abstrahiert die TestContainers-API und bietet eine auf den konkreten Dienst zugeschnittene Schnittstelle.
Auf den ersten Blick scheint Docker Compose eine Alternative zu sein, das ebenfalls Container für Tests starten kann. Der Unterschied liegt jedoch in der Herangehensweise: Docker Compose arbeitet deklarativ mit YAML-Dateien und richtet typischerweise eine geteilte Umgebung für mehrere Tests ein. TestContainers hingegen ist programmatisch und integriert sich direkt in den Testcode. Jeder Test kann seine eigene Containerkonfiguration haben, Container werden im laufenden Betrieb gestartet und wieder gestoppt.
Ein weiterer Unterschied: Bei Compose muss man explizit darauf achten, Container zwischen verschiedenen Tests zurückzusetzen. Bei TestContainers ist das Design von Anfang an auf Isolation ausgelegt. Jeder Test bekommt neue Container, was sie robuster und unabhängiger voneinander macht.
Mehr Idee als Projekt
TestContainers ist kein monolithisches Open-Source-Projekt, sondern eher eine Idee, die in verschiedenen Programmiersprachen umgesetzt wurde. Es gibt TestContainers für Java, Go, .NET, Node.js, Python, PHP, Rust und zahlreiche weitere Sprachen – entwickelt von verschiedenen Maintainer-Teams mit unterschiedlichen Schwerpunkten.
Das bedeutet, dass beispielsweise Features, die in der Java-Implementierung selbstverständlich sind, in der Python-Version fehlen können – und umgekehrt. Auch die API-Gestaltung unterscheidet sich zwischen den Programmiersprachen, selbst wenn die Konzepte gleich bleiben. Die Dokumentationsqualität variiert und die Reife der Implementierungen ebenso.
Die Community und der Support sind pro Sprache organisiert: Hilfe zur Go-Implementierung findet man in anderen Foren als Hilfe zur PHP-Version.
Man sollte nicht davon ausgehen, dass ein bestimmtes Feature existiert, nur weil man es aus einer anderen Sprache kennt. Ein Blick in die Dokumentation der jeweiligen Implementierung ist unerlässlich. Die gute Nachricht: Die Grundkonzepte sind überall gleich. Wer das Prinzip verstanden hat, findet sich grundsätzlich auch in anderen Implementierungen zügig zurecht.
Ein Praxisbeispiel
Um die Unterschiede zwischen TestContainers-Implementierungen konkret zu zeigen, dient die Datenbank EventSourcingDB als Beispiel. Dabei handelt es sich um eine auf Event Sourcing spezialisierte, von the native web entwickelte Datenbank. Sie ist Closed Source, aber die zugehörigen Client-SDKs (Software Development Kits) sind Open Source auf GitHub verfügbar.
EventSourcingDB steht dabei exemplarisch für einen typischen Service, den man in Anwendungen benötigt – sei es eine Datenbank, eine Message-Queue oder ein anderer Infrastrukturdienst. Der entscheidende Vorteil für unser Beispiel: EventSourcingDB startet in weniger als einer Sekunde, was den „Container pro Test“-Ansatz praktikabel macht. Die Client-SDKs für verschiedene Sprachen enthalten jeweils eine eigene TestContainers-Integration, deren Implementierung sich lohnt anzuschauen.
Dieser Artikel betrachtet die Go- und PHP-Implementierung im Detail. Beide verfolgen konzeptionell den gleichen Ansatz, unterscheiden sich aber in wichtigen Details. Daher eignen sich die Implementierungen gut, um die Unterschiede zwischen TestContainers-Implementierungen zu illustrieren.
Entwicklung & Code
Programmiersprache Python: Performante Algorithmen entwickeln und optimieren
Plant man eine Reise durch mehrere Städte und will die kürzeste Route finden, greift man auf Algorithmen zurück, eine wohldefinierte Abfolge deterministischer Operationen. Dieser Artikel begleitet den Entwicklungsprozess eines Algorithmus, der kürzeste Wege zwischen Städten findet. Er zeigt Schritt für Schritt den Weg von der ersten Skizze über Tests und Visualisierung mit Matplotlib und NetworkX bis zur Optimierung durch geeignete Datenstrukturen. So entsteht ein Programm, das nicht nur funktional korrekt arbeitet, sondern auch performant ist.
Weiterlesen nach der Anzeige

Michael Inden ist Java- und Python-Enthusiast mit über zwanzig Jahren Berufserfahrung. Derzeit ist er als Head of Development tätig, spricht auf Konferenzen und schreibt Fachbücher über Java und Python.
Ziel ist, in einem Straßennetz diejenigen Wege zu finden, die Städte am kürzesten verbinden. Zur Modellierung kann man Graphen verwenden. In Abbildung 1 repräsentieren Kreise mit Beschriftung die Städte und die Verbindungslinien mit Zahlen entsprechen Wegen mit Distanzen.

Ein Graph visualisiert die Abstände von Städten; die Zahlen stehen für die Entfernungen (Abb. 1).
Für diese vereinfachte Karte soll der kürzeste Weg von A nach D gefunden werden. Während man bei wenigen Städten und Verbindungen alle Möglichkeiten ausprobieren kann, wird der Ansatz aufwendiger, je mehr Städte und Verbindungen existieren. Folgende Verbindungen sind möglich, wobei 13 die schlechteste ist und 6 die beste:
A -> B -> C -> D => 5 + 1 + 7 = 13
A -> C -> B -> D => 2 + 1 + 3 = 6
A -> C -> D => 2 + 7 = 9
A -> B -> D => 5 + 3 = 8
Mit der O-Notation die Effizienz verstehen
Für eine gute Bedienbarkeit von Programmen ist relevant, wie schnell sich Berechnungen und Operationen ausführen lassen. Das gilt vor allem bei großen Datenmengen. Die O-Notation erlaubt es, Algorithmen zu klassifizieren und das Wachstum der Laufzeit (oder des Speicherbedarfs) eines Algorithmus zu beschreiben, wenn die Eingabemenge größer wird. Somit sind Effekte vorhersagbar, etwa wenn eine Liste nicht mehr 10 oder 20, sondern 100.000 und mehr Daten enthält.
Weiterlesen nach der Anzeige
Die O-Notation hilft, die Laufzeit von Operationen einzuschätzen. Sie ordnet Algorithmen und Funktionen in Komplexitätsklassen ein. Bei O(n³) wächst die Anzahl der Schritte mit der dritten Potenz der Eingabemenge. Bei 100 Eingabedaten ergibt sich ein Aufwand von 1003 für die Berechnung, also 1.000.000 Schritte. Je niedriger die Komplexitätsklasse ist, desto besser. Weitere Klassen zeigt die Tabelle „O-Notation mit in Komplexitätsklassen eingeteilten Algorithmen“, Abbildung 2 visualisiert die Effekte.
| O-Notation mit in Komplexitätsklassen eingeteilten Algorithmen | ||
| Notation | Bedeutung, Wachstum | Beispiel |
| O(1) | konstant | Zugriff auf ein Listenelement |
| O(log n) | logarithmisch | Binärsuche |
| O(n) | linear | einfache Schleife über alle Elemente |
| O(n log n) | linear-logarithmisch | effiziente Sortieralgorithmen (etwa Mergesort) |
| O(n²) | quadratisch | zweifach verschachtelte Schleife |
| O(n3) | kubisch | dreifach verschachtelte Schleife |

Die Graphen zeigen die Anzahl der Operationen in Abhängigkeit von der Eingabegröße (Abb. 2).
Eine Klassifikation mit der O-Notation ist insbesondere wichtig, um Laufzeiten unabhängig von Hardwareausstattung, Implementierungsdetails und gewählten Programmiersprachen bezüglich ihrer Skalierungseigenschaften zu vergleichen.
Für eine vereinfachte Einschätzung betrachtet man bei der Bewertung nur den dominierenden Term, da bei großen Eingabegrößen kleine Konstanten oder niedrigere Terme und Faktoren vernachlässigbar sind. In der Formel n3 + 4n² + 3n + 7 folgt durch die Vereinfachungen die Laufzeitklasse O(n3).
Von der Idee zum Programm
Ein systematisches Vorgehen ist selbst für kleinere Programme und vor allem bei komplexen Softwareprojekten der Schlüssel zu funktionalem, wartbarem und performantem Code.
1. Problem verstehen und analysieren
- klären, welches Problem zu lösen ist, und es in Teilaufgaben zerlegen;
- prüfen, ob es bereits bewährte Lösungen für Teilaufgaben gibt, beispielsweise Binärsuche für performante Suchen in sortierten Datenbeständen, Dijkstra-Algorithmus für kürzeste Wege;
- Eingabe- und Ausgabedaten definieren;
- Randbedingungen und Sonderfälle berücksichtigen.
2. Planen und eine Grobstruktur entwickeln
- Problem in Teilaufgaben zerlegen;
- Abläufe in natürlicher Sprache formulieren oder skizzieren;
- geeignete Datenstrukturen wählen (Listen, Dictionaries, Heaps).
3. Implementierung
- Sourcecode in klar getrennte Funktionen oder Klassen gliedern;
- auf Lesbarkeit und Verständlichkeit achten, aussagekräftige Namen und (falls sinnvoll) ergänzende Kommentare verwenden;
- vorhandene Bibliotheken nutzen, um Entwicklungszeit zu sparen (etwa Matplotlib zur Visualisierung).
4. Testen (Dry-Run- und Unit-Tests)
- Funktionsweise ausprobieren;
- Unit-Tests schreiben, um die Funktionsweise zu prüfen und Rand- und Sonderfälle abzudecken.
5. Performance messen
- Messungen mit kleinen, mittleren und großen Datenbeständen ausführen, etwa mit 100, 10.000 und 1.000.000 Datensätzen;
- Engpässe identifizieren – sie zeigen sich allerdings meist erst bei sehr großen Datenbeständen.
6. Optimieren
Wurden in Schritt 5 Schwachstellen aufgedeckt, sollte man die Umsetzung und die gewählten Algorithmen für Teilprobleme nochmals genauer anschauen.
- O-Notation verwenden, um die Komplexität formal zu bewerten: Was läuft in Schleifen? Wie und wo erfolgt eine Suche – linear oder mit Binärsuche? Für verschiedene Aktionen kann das Laufzeiten von O(1)
, O(log n) oder O(n)bedeuten. - besser geeignete Algorithmen oder effizientere Datenstrukturen einsetzen.
Implementierung und Test miteinander verweben
In der Praxis laufen die Schritte 3 und 4 nicht immer unabhängig voneinander. Wenn sich die Ergebnisse gut vorhersagen lassen, bietet es sich an, mit dem Erstellen von Testfällen zu starten. Manchmal braucht es aber erst einmal eine Idee und einen Prototyp der Implementierung. Gerade bei größeren Programmierprojekten ergeben sich weitere Anforderungen während der Implementierungs- und Testphase.
Der folgende Ablauf hat sich in der Praxis bewährt und lässt sich auch beim Entwickeln eines Algorithmus anwenden.
Entwicklung & Code
GitLab 18.8: Duo Agent Platform jetzt allgemein verfügbar
Mit GitLab 18.8 stellt GitLab die Duo Agent Platform allgemein zur Verfügung. Sie soll Unternehmen dabei unterstützen, KI-Agenten für Planung, Entwicklung, Absicherung und Auslieferung von Software koordiniert einzusetzen.
Weiterlesen nach der Anzeige
Einheitlicher Ansatz für KI in der Softwareentwicklung
GitLab reagiert damit auf ein bekanntes Problem beim Einsatz von KI in der Softwareentwicklung: KI-Tools steigern zwar die Produktivität einzelner Entwicklerinnen und Entwickler, verlieren diesen Effekt aber oft auf Teamebene. Die Duo Agent Platform orchestriert KI-Agenten deshalb innerhalb eines einheitlichen Systems und nutzt einen gemeinsamen Projektkontext aus Issues, Merge Requests, Pipelines und Security-Findings.
Lesen Sie auch
KI-Agenten, Chat und Automatisierung
Die Plattform kombiniert konversationelle KI, spezialisierte Agenten und automatisierte Workflows. Ein zentraler Baustein ist der Agentic Chat, der in der GitLab-Oberfläche und in verschiedenen Entwicklungsumgebungen zur Verfügung steht. Er unterstützt beim Erstellen von Code, bei der Analyse und Fehlerbehebung, bei Tests und Dokumentation auf Basis des aktuellen Projektkontexts.
Der Planner Agent ist nun ebenso allgemein verfügbar und soll Produktmanager in GitLab bei der Arbeit mit Work Items unterstützen. Er kann unter anderem beim Analysieren von Backlogs, beim Priorisieren (z. B. mit RICE oder MoSCoW) und beim Aufbereiten von Planungsinformationen helfen.
Weiterlesen nach der Anzeige
Katalog, Agenten und Flows
Mit dem AI Catalog können Teams Agenten und Workflows organisationsweit bereitstellen und teilen. Vorgefertigte Agenten übernehmen typische Aufgaben wie Planung oder Sicherheitsanalyse. Flows automatisieren wiederkehrende Abläufe, etwa das Erstellen von Merge Requests, die Anpassung von CI/CD-Pipelines oder die Analyse fehlgeschlagener Builds.
Auch der GitLab Duo Security Analyst Agent ist mit GitLab 18.8 aus der Beta-Phase in die allgemeine Verfügbarkeit übergegangen. Er ermöglicht es, Schwachstellen per natürlicher Sprache im GitLab Duo Agentic Chat zu verwalten, und ist dort standardmäßig ohne zusätzliche Einrichtung verfügbar.
Betrieb und Abrechnung
Die Duo Agent Platform ist auf GitLab.com und in GitLab Self-Managed verfügbar, GitLab Dedicated soll folgen. Transparenz- und Governance-Funktionen unterstützen den Unternehmenseinsatz. Die Abrechnung erfolgt nutzungsabhängig über GitLab Credits aus einem gemeinsamen Pool. Weitere Informationen finden sich im entsprechenden Blogbeitrag.
(mdo)
Entwicklung & Code
software-architektur.tv: Spec-Driven Development mit Simon Martinelli
In dieser Episode spricht Ralf D. Müller mit Simon Martinelli über den AI Unified Process (AIUP), einen agilen und iterativen Entwicklungsansatz, der Requirements ins Zentrum stellt – nicht den Code. Martinelli zeigt, wie man mit AIUP moderne Software entwickelt, bei der Anforderungen, Spezifikationen, Code und Tests gemeinsam durch kurze Iterationen wachsen, während KI als Konsistenz-Engine dient.
Weiterlesen nach der Anzeige
Das Duo diskutiert die zentrale Frage: Braucht es perfekte, deterministische Spezifikationen für KI-Code-Generierung? Simon Martinelli argumentiert, dass das der falsche Ansatz ist. Stattdessen ermöglicht AIUP iterative Verbesserung: Requirements treiben die Entwicklung, Spezifikationen werden detaillierter und Tests schützen das Systemverhalten, während der generierte Code sich gemeinsam mit allem anderen weiterentwickelt.
Lisa Maria Schäfer malt dieses Mal keine Sketchnotes.
Livestream am 16. Januar
Die Ausstrahlung findet am Freitag, 16. Januar 2026 live ab 13:00 Uhr statt. Die Folge steht im Anschluss als Aufzeichnung bereit. Während des Livestreams können Interessierte Fragen via Twitch-Chat, YouTube-Chat oder anonym über das Formular auf der Videocast-Seite einbringen.
software-architektur.tv ist ein Videocast von Eberhard Wolff, Blogger sowie Podcaster auf iX und bekannter Softwarearchitekt, der als Head of Architecture bei SWAGLab arbeitet. Zum Team gehören außerdem Lisa Maria Schäfer (Socreatory) und Ralf D. Müller (DB Systel). Seit Juni 2020 sind über 250 Folgen entstanden, die unterschiedliche Bereiche der Softwarearchitektur beleuchten – mal mit Gästen, mal Wolff, Schäfer oder Müller solo. Seit mittlerweile mehr als zwei Jahren bindet iX (heise Developer) die über YouTube gestreamten Episoden im Online-Channel ein, sodass Zuschauer dem Videocast aus den Heise Medien heraus folgen können.
Weitere Informationen zu den Folgen finden sich auf der Videocast-Seite.
Weiterlesen nach der Anzeige
(mdo)
-
UX/UI & Webdesignvor 3 MonatenIllustrierte Reise nach New York City › PAGE online
-
UX/UI & Webdesignvor 3 MonatenSK Rapid Wien erneuert visuelle Identität
-
Entwicklung & Codevor 2 MonatenKommandozeile adé: Praktische, grafische Git-Verwaltung für den Mac
-
Künstliche Intelligenzvor 3 MonatenX: Für Dauer von Bezahlabo kann man bald ungenutzte Kontonamen übernehmen
-
UX/UI & Webdesignvor 3 MonatenArndt Benedikt rebranded GreatVita › PAGE online
-
Künstliche Intelligenzvor 3 WochenSchnelles Boot statt Bus und Bahn: Was sich von London und New York lernen lässt
-
Online Marketing & SEOvor 3 Monaten3 Creator to watch: Diese TikToker haben im September für Aufsehen gesorgt
-
Entwicklung & Codevor 1 MonatKommentar: Anthropic verschenkt MCP – mit fragwürdigen Hintertüren
