Integrationstests in C# mit Docker: Von A bis Z
\n\nIntegrationstests sind ein kritisch wichtiger Schritt bei der Entwicklung jeder ernsthaften C#-Anwendung. Sie prüfen, wie verschiedene Systemkomponenten (Datenbank, externe APIs, Dateisysteme) zusammenarbeiten. Die Einrichtung der Testumgebung wird jedoch oft zum Kopfzerbrechen: Man muss echte Server hochfahren, Daten nach Tests bereinigen und mit instabilen Umgebungen kämpfen. Docker löst diese Probleme, indem es leichte, isolierte und reproduzierbare Container bereitstellt. In diesem Artikel zeigen wir, wie Sie Integrationstests in C# mit Docker von Null bis zur funktionierenden Pipeline einrichten.
\n\nWarum ist Docker ideal für Integrationstests in C#?
\n\nDer traditionelle Ansatz – die Verwendung lokaler SQL Server-Datenbanken oder Emulatoren externer Dienste – führt zu Problemen:
\n- \n
- Datenverschmutzung: Tests hinterlassen Müll in der Datenbank und beeinflussen andere Tests. \n
- Umgebungsinkompatibilität: Auf dem Entwicklerrechner läuft eine DBMS-Version, auf dem CI-Server eine andere.
- Schwierigkeiten beim parallelen Ausführen: Tests geraten in Konflikt um Ports und Ressourcen.
Docker löst dies einfach: Jeder Test (oder jede Testgruppe) erhält seinen eigenen isolierten Container mit der benötigten Version der Datenbank, Redis oder eines anderen Dienstes. Container sind leicht, starten in Sekunden und werden nach Abschluss der Tests garantiert zerstört. Für .NET-Entwickler ist dies dank der Bibliothek Testcontainers for .NET besonders relevant, die die Containerverwaltung direkt aus dem Testcode heraus automatisiert.
\n\nProjekteinrichtung: Docker zu C#-Tests hinzufügen
\n\nZunächst erstellen wir ein Projekt mit Integrationstests. Angenommen, wir haben eine Web-API auf .NET 8, die mit PostgreSQL arbeitet. Wir müssen den Endpunkt zum Erstellen eines Benutzers testen.
\n\nSchritt 1: Installation der NuGet-Pakete
\nFügen Sie dem Testprojekt die folgenden Pakete hinzu:
\ndotnet add package Testcontainers.PostgreSql\ndotnet add package Microsoft.AspNetCore.Mvc.Testing\ndotnet add package FluentAssertions\n\nTestcontainers.PostgreSql ist ein Wrapper um das Docker SDK, der PostgreSQL-Container verwaltet. Microsoft.AspNetCore.Mvc.Testing ermöglicht das Ausführen der Webanwendung im Arbeitsspeicher zum Testen.
Schritt 2: Erstellen einer Basisklasse für Tests
\nWir erstellen eine abstrakte Klasse, die vor den Tests einen Container mit der Datenbank startet:
\nusing Testcontainers.PostgreSql;\nusing Xunit;\n\npublic abstract class IntegrationTestBase : IAsyncLifetime\n{\n private readonly PostgreSqlContainer _postgresContainer;\n\n protected string ConnectionString => _postgresContainer.GetConnectionString();\n\n protected IntegrationTestBase()\n {\n _postgresContainer = new PostgreSqlBuilder()\n .WithImage("postgres:16-alpine")\n .WithDatabase("testdb")\n .WithUsername("test")\n .WithPassword("test123")\n .Build();\n }\n\n public async Task InitializeAsync()\n {\n await _postgresContainer.StartAsync();\n }\n\n public async Task DisposeAsync()\n {\n await _postgresContainer.StopAsync();\n }\n}\n\nDiese Klasse implementiert IAsyncLifetime von xUnit, was den Start des Containers vor allen Tests und dessen Stopp danach garantiert. ConnectionString wird dynamisch aus dem Container bezogen – der Port kann ein beliebiger freier Port sein.
Schritt 3: Schreiben eines Tests mit Testcontainers und WebApplicationFactory
\nJetzt schreiben wir den eigentlichen Test. Wir verwenden WebApplicationFactory, um einen Test-HTTP-Client zu erstellen:
using Microsoft.AspNetCore.Mvc.Testing;\nusing FluentAssertions;\nusing System.Net.Http.Json;\n\npublic class UserApiTests : IntegrationTestBase\n{\n private readonly WebApplicationFactory<Program> _factory;\n\n public UserApiTests()\n