Integrationstests C# mit Docker: Fortgeschrittenes Niveau
\nIntegrationstests sind ein entscheidender Schritt zur Qualitätssicherung in modernen .NET-Anwendungen. Die Verwendung von Docker ermöglicht die Erstellung isolierter, reproduzierbarer Umgebungen, die der Produktion möglichst nahe kommen. In diesem Artikel betrachten wir fortgeschrittene Techniken für Integrationstests in C# mit Docker: von der Einrichtung von Testcontainers bis zur Organisation von CI/CD-Pipelines.
\nDas Material richtet sich an Entwickler, die bereits mit den Grundlagen von Unit-Tests und den grundlegenden Konzepten von Docker vertraut sind. Wir vertiefen uns in die Verwaltung des Lebenszyklus von Containern, die Arbeit mit mehreren Diensten, das Debugging und die Optimierung der Testlaufzeit.
\n\n1. Einrichtung von Testcontainers für .NET
\nTestcontainers ist eine Bibliothek, die Docker-Container aus dem Testcode heraus verwaltet. Sie erstellt, startet und stoppt Container automatisch und gewährleistet so die Isolierung jedes Tests.
\nInstallieren Sie zunächst das Paket in Ihrem Testprojekt:
\ndotnet add package Testcontainers\nEin grundlegendes Beispiel – Testen eines Repositorys mit PostgreSQL:
\nusing Testcontainers.PostgreSql;\nusing Xunit;\n\npublic class UserRepositoryTests : IAsyncLifetime\n{\n private readonly PostgreSqlContainer _postgresContainer;\n\n public UserRepositoryTests()\n {\n // Container mit PostgreSQL konfigurieren\n _postgresContainer = new PostgreSqlBuilder()\n .WithImage("postgres:15")\n .WithDatabase("testdb")\n .WithUsername("test")\n .WithPassword("test123")\n .WithCleanUp(true)\n .Build();\n }\n\n public async Task InitializeAsync()\n {\n // Container vor allen Tests starten\n await _postgresContainer.StartAsync();\n }\n\n public async Task DisposeAsync()\n {\n // Container stoppen und entfernen\n await _postgresContainer.DisposeAsync();\n }\n\n [Fact]\n public async Task AddUser_ShouldCreateUser()\n {\n // Verbindungszeichenfolge zum Container abrufen\n var connectionString = _postgresContainer.GetConnectionString();\n var repository = new UserRepository(connectionString);\n\n await repository.AddUserAsync(new User { Name = "Test User" });\n var user = await repository.GetUserByNameAsync("Test User");\n\n Assert.NotNull(user);\n Assert.Equal("Test User", user.Name);\n }\n}\nWichtig: Verwenden Sie IAsyncLifetime zur Container-Verwaltung. Dies stellt sicher, dass jede Testklasse eine frische Datenbankinstanz erhält.
2. Multi-Container-Architektur mit Docker Compose
\nReale Anwendungen sind von mehreren Diensten abhängig: Datenbanken, Nachrichtenwarteschlangen, Caches. Testcontainers unterstützt Docker Compose, sodass eine gesamte Infrastruktur gestartet werden kann.
\nInstallieren Sie das zusätzliche Paket:
\ndotnet add package Testcontainers.Compose\nBeispiel einer Datei docker-compose.test.yml:
version: '3.8'\nservices:\n postgres:\n image: postgres:15\n environment:\n POSTGRES_USER: test\n POSTGRES_PASSWORD: test\n POSTGRES_DB: testdb\n redis:\n image: redis:7-alpine\nVerwendung im Test:
\nusing Testcontainers.Compose;\n\npublic class OrderServiceTests\n{\n private readonly DockerComposeContainer _compose;\n\n public OrderServiceTests()\n {\n _compose = new DockerComposeContainer()\n .WithComposeFilePath("docker-compose.test.yml")\n .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Testing")\n .Build();\n }\n\n [Fact]\n public async Task CreateOrder_ShouldSaveToDbAndCache()\n {\n await _compose.StartAsync();\n \n var dbConnection = _compose.GetConnectionString("postgres", 5432);\n var redisConnection = _compose.GetConnectionString("redis", 6379