Today I Learned #1 — Testcontainers

Marcel Prehn
Nov 15, 2019 · 2 min read

Use Case

Man stelle sich folgendes Szenario vor: Ein Spring Boot Microservice, Unit Tests mit H2 In-Memory Datenbank, integrative Tests dann produktionsnah mit einer PostgreSQL DB.

Kommt man nun auf die Idee ein Feature zu benutzen, das — nennen wir es mal Postgres-nativ ist — stößt man in den Unit Tests schnell an die Grenzen der H2-Datenbank. In diesem Fall bei Benutzung des JSONB-Datentyps. Dieser erlaubt es, ähnlich wie in einem Document Storage, JSON-Objekte in einer Spalte zu persistieren. Dabei sind alle Felder des Objektes such-, änder- und indizierbar. Also ein Kompromiss zwischen klassischer relationaler Datenbank und NoSQL-Ansätzen à la MongoDB. Sounds fair! 🧐

Das Problem

Nun lässt sich der Datentyp JSONB allerdings nicht mit H2, HSQLDB oder analogen In-Mem Datenbanken nutzen. Eine lauffähige embedded Postgres gibt es auch nicht. Bleibt also nur der Verzicht von Datenbanktests auf Unit Test Ebene (👎🏻 ) oder das Nutzen einer Standalone Postgres Instanz auf dem Entwicklerrechner (noch mehr 👎🏻). Ooooooder …

Die Lösung

.. man nutzt Testcontainer!

Statt also eine In-Memory Datenbank zu erzeugen, wird für den Test ein Container mit einem definierten Image gestartet. Die Anwendung wird dann, beispielsweise über die application.yaml, entsprechend für diesen Container konfiguriert. Was braucht man dafür?

Als erstes die entsprechenden Dependencies in die build.gradle:

testImplementation("org.testcontainers:testcontainers:1.12.3")
testImplementation("org.testcontainers:postgresql:1.12.3")

Dann habe ich ein Test-Profil angelegt, dass die Verbindung für den Unit Test entsprechend in der application-test.yml konfiguriert:

spring:
datasource:
url: jdbc:tc:postgresql:9.6.3://localhost/db
username: user
password:
driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver

In der Test-Klasse wird dann nur noch das Test-Profil gesetzt und schon sollte beim Start des Unit Tests das Postgres-Image geladen und als Container gestartet werden.

@SpringBootTest 
@ActiveProfiles("test")
class Test {
...
}

Das Image liegt dann in guter alter Docker-Manier übrigens auf dem Client und muss natürlich beim nächsten Run nicht wieder gezogen werden.

Fazit

Mit Hilfe von Testcontainern lassen sich relativ schnell und einfach produktionsnahe Bedingungen für Unit Tests erzeugen. Das dabei die Laufzeit in Mitleidenschaft gezogen wird sollte Jedem bewusst sein. Aber einen Tod muss man halt sterben … 🤷🏻‍♂️

marcel.works

Marcel Prehn

Written by

Java Enterprise Development by Day, Technological Nonsense by Night. #Java #GoLang #IoT #AWS

marcel.works

Technological Nonsense

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade