Integrationstests von Kotlin mit Docker: Fortgeschrittenes Niveau
\n\nIntegrationstests sind ein kritisch wichtiger Schritt in der Entwicklung moderner Mikroservices mit Kotlin. Die Verwendung von Docker ermöglicht die Erstellung isolierter, reproduzierbarer Umgebungen, die der Produktion so nahe wie möglich kommen. In diesem Artikel betrachten wir fortgeschrittene Techniken für Integrationstests von Kotlin-Anwendungen mit Docker, einschließlich Testcontainers, Leistungsoptimierung und CI/CD-Integration.
\n\n1. Einrichtung von Testcontainers für ein Kotlin-Projekt
\n\nTestcontainers ist eine Bibliothek für JUnit, die den Lebenszyklus von Docker-Containern direkt aus den Tests heraus verwaltet. Für Kotlin bietet sie praktische DSL-Erweiterungen.
\n\n1.1. Einbinden der Abhängigkeiten
\n\nFügen Sie die folgenden Abhängigkeiten zu Ihrer build.gradle.kts hinzu:
testImplementation("org.testcontainers:testcontainers:1.19.3")\ntestImplementation("org.testcontainers:postgresql:1.19.3")\ntestImplementation("org.testcontainers:junit-jupiter:1.19.3")\ntestImplementation("org.jetbrains.kotlin:kotlin-test")\n\n1.2. Einfaches Beispiel mit PostgreSQL
\n\nBetrachten wir einen Test für ein Repository, das mit PostgreSQL arbeitet:
\n\nimport org.junit.jupiter.api.Test\nimport org.testcontainers.containers.PostgreSQLContainer\nimport org.testcontainers.junit.jupiter.Container\nimport org.testcontainers.junit.jupiter.Testcontainers\n\n@Testcontainers\nclass UserRepositoryTest {\n\n companion object {\n @Container\n val postgres = PostgreSQLContainer<Nothing>("postgres:15-alpine").apply {\n withDatabaseName("testdb")\n withUsername("test")\n withPassword("test")\n }\n }\n\n @Test\n fun `should save and retrieve user`() {\n val dataSource = createDataSource(postgres.jdbcUrl, postgres.username, postgres.password)\n val repository = UserRepository(dataSource)\n\n val user = User(id = null, name = "Alice", email = "alice@example.com")\n val saved = repository.save(user)\n\n val found = repository.findById(saved.id!!)\n assert(found?.name == "Alice")\n }\n\n private fun createDataSource(jdbcUrl: String, username: String, password: String): DataSource {\n // HikariCP oder ein anderer Verbindungspool\n return HikariDataSource(HikariConfig().apply {\n this.jdbcUrl = jdbcUrl\n this.username = username\n this.password = password\n driverClassName = "org.postgresql.Driver"\n })\n }\n}\n\nTestcontainers startet den Container automatisch vor den Tests und stoppt ihn nach deren Abschluss. Dies gewährleistet eine saubere Testumgebung.
\n\n2. Testen mehrerer Dienste mit Docker Compose
\n\nIn realen Mikroservices ist oft die Interaktion mit mehreren externen Systemen erforderlich: Datenbanken, Nachrichtenwarteschlangen, Caches. Verwenden Sie DockerComposeContainer, um den gesamten Stack hochzufahren.
2.1. Konfiguration von Docker Compose
\n\nErstellen Sie eine Datei docker-compose-test.yml:
version: '3.8'\nservices:\n postgres:\n image: postgres:15-alpine\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: test\n POSTGRES_PASSWORD: test\n redis:\n image: redis:7-alpine\n rabbitmq:\n image: rabbitmq:3-management-alpine\n\n2.2. Integrationstest mit Docker Compose
\n\nBeispiel eines Tests, der die Interaktion des Dienstes mit der Datenbank, dem Cache und der Warteschlange überprüft:
\n\nimport org.junit.jupiter.api.Test\nimport org.testcontainers.containers.DockerComposeContainer\nimport org.testcontainers.junit.jupiter.Container\nimport org.testcontainers.junit.jupiter.Testcontainers\nimport java.io.File\n\n@Testcontainers\nclass OrderServiceIntegrationTest {\n\n companion object {\n @Container\n val environment = DockerComposeContainer(\n File("src/test/resources/docker-com