Cassandra 4 mit Testcontainers in Spring Boot
Cassandra 4 ist ein lang erwartetes Release der Cassandra Datenbank.
Dabei hat sich nicht nur einiges in der Datenbank selbst geändert, sondern auch die Java Libraries für den Zugriff haben einige API Änderungen erfahren.
In dem Zuge sind viele andere Projekte aktuell noch nicht soweit, gute Unterstützung für Cassandra 4 zu bieten.
Spring Boot bzw. Spring Data Cassandra ist jedoch bereits soweit, dass aktuelle Treiber genutzt werden.
Dort stellt sich die Frage, wie das Thema Unit Test bzw. Integrationstest mit Cassandra 4 umgesetzt werden kann.
Es gibt für Cassandra einige Unit-Test Ansätze, die zum Teil einen Embedded-Cassandra-Cluster starten können.
Mit neueren Cassandra-Versionen, speziell Version 4, und aktuellen JDK-Versionen funktioniert das jedoch nicht.
Abhilfe kann da das Testcontainers-Projekt schaffen - Cassandra wird dann einfach als (Docker) Container gestartet und kann ganz normal verwendet werden.
Testcontainers selbst bietet für Cassandra in Version 3.x expliziten Support, für Cassandra 4 ist das jedoch auch schnell durch einen GenericContainer
konfiguriert.
Als Beispiel dient eine Spring Boot 2.6 Anwendung mit Spring Data Cassandra als zusätzliche Abhängigkeit. Zunächst muss Testcontainers als Abhängigkeit hinzugefügt werden, hier mit Maven gezeigt.
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.16.2</version>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.16.2</version>
</dependency>
Für Spring Boot kann dann ein Test angelegt werden, der duch @Testcontainers
die Integration mit dem Testcontainers Framework herstellt.
Da der Test auf einem Cassandra Schema arbeiten soll und Cassandra als leere Instanz für den Test bereitgestellt wird, kann durch das Spring Boot-Property spring.data.cassandra.schema-action=create
ein Schema erzeugt werden.
Dazu muss Cassandra selbst als @Container
ebenfalls definiert werden.
Als Timeout sollte - je nach Umgebung - ein Wert im Minutenbereich gewählt werden.
Nun fehlt lediglich noch der Cassandra Keyspace.
Im Beispiel wird eine entsprechende Konfiguration als @TestConfiguration
definiert, die zusätzlich zur regulären Spring @Configuration
herangezogen wird.
Damit Spring Data Cassandra die Verbindung zu der per Container bereitgestellten Cassandra-Instanz herstellen kann, ist es am einfachsten, eine @DynamicPropertySource
zu verwenden und damit die Cassandra Contactpoints zu konfigurieren.
@SpringBootTest(properties = "spring.data.cassandra.schema-action=create")
@Testcontainers
public class TestcontainersCassandraTest
{
@Container
public static GenericContainer cassandra = new GenericContainer("cassandra:4")
.withExposedPorts(9042)
.waitingFor(
new LogMessageWaitStrategy().withRegEx(".*Starting listening for CQL clients.*")
.withStartupTimeout(Duration.of(2, ChronoUnit.MINUTES)));
@DynamicPropertySource
static void configure(DynamicPropertyRegistry registry)
{
registry.add("spring.data.cassandra.contact-points", () ->
String.format("%s:%s", cassandra.getContainerIpAddress(), cassandra.getMappedPort(9042)));
}
@TestConfiguration
public static class CassandraConfiguration extends AbstractCassandraConfiguration
{
@Override
protected List<CreateKeyspaceSpecification> getKeyspaceCreations()
{
var specification = CreateKeyspaceSpecification
.createKeyspace("demo").ifNotExists()
.with(KeyspaceOption.DURABLE_WRITES, true)
.withSimpleReplication();
return List.of(specification);
}
@Override
protected String getKeyspaceName()
{
return "demo";
}
}
// ... test methods ...
}
Mit diesem Grundgerüst können nun Tests durchgeführt werden. Da der Aufbau des Cassandra Testclusters relativ zeitaufwändig ist, sollten die Integrationstests entsprechend gebündelt werden.
Zu den Themen Cassandra, Docker und Kubernetes bieten wir sowohl Beratung, Entwicklungsunterstützung als auch passende Schulungen an:
Auch für Ihren individuellen Bedarf können wir Workshops und Schulungen anbieten. Sprechen Sie uns gerne an.