eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – LJB – NPI EA (cat = Core Java)
announcement - icon

Code your way through and build up a solid, practical foundation of Java:

>> Learn Java Basics

1. Overview

Apache Cassandra is an open-source distributed NoSQL database. It was designed to handle large amounts of data with fast read-write performance and with no single point of failure.

In this tutorial, we’ll look at testing a Spring Boot application that uses a Cassandra database. We’ll explain how to set up integration tests using a Cassandra container from the Testcontainers library. In addition, we’ll make use of the Spring Data repository abstraction to work with Cassandra’s data layer.

Finally, we’ll show how to reuse a shared Cassandra container instance across multiple integration tests.

2. Test Containers

Testcontainers is a Java library that provides lightweight, throwaway instances of Docker containers. Hence, we commonly use it in Spring for integration testing of applications that use databases. Testcontainers enables us to test on a real database instance without requiring us to install and manage the database on our local machine.

2.1. Maven Dependencies

Cassandra containers are available in the Cassandra Testcontainers module. This enables the usage of containerized Cassandra instances.

Unlike the cassandra-unit library, the Testcontainers library is fully compatible with JUnit 5. Let’s start by listing the required Maven dependencies:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>1.19.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>cassandra</artifactId>
    <version>1.19.5</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>1.19.5</version>
    <scope>test</scope>
<dependency>

2.2. Cassandra Container

Containerized database instances are commonly used for integration testing. As well as ensuring that our data access layer code is fully compatible with the specific database version.

To begin with, we’ll need to annotate our test class with both @SpringBootTest and @Testcontainers:

@SpringBootTest
@Testcontainers
class CassandraSimpleIntegrationTest {}

Then, we can define a Cassandra container and expose its specific port:

public static final CassandraContainer<?> cassandra 
  = new CassandraContainer<>("cassandra:3.11.2").withExposedPorts(9042);

Here we’re exposing the container port 9042. We should note, however, that Testcontainers will link it to a random host port, which we can get later on.

Using the above, the Testcontainers library automatically takes care of starting a dockerized Cassandra container instance for us aligned with the lifecycle of the test class:

@Test
void givenCassandraContainer_whenSpringContextIsBootstrapped_thenContainerIsRunningWithNoExceptions() {
    assertThat(cassandra.isRunning()).isTrue();
}

Now we have a running Cassandra container. However, the Spring application does not yet know about it.

2.3. Overriding Test Properties

In order for Spring Data to be able to establish a connection with the Cassandra container, we’ll need to provide a few connection properties. We’ll override the default Cassandra connection properties by defining system properties via the java.lang.System class:

@BeforeAll
static void setupCassandraConnectionProperties() {
    System.setProperty("spring.cassandra.keyspace-name", KEYSPACE_NAME);
    System.setProperty("spring.cassandra.contact-points", cassandra.getContainerIpAddress());
    System.setProperty("spring.cassandra.port", String.valueOf(cassandra.getMappedPort(9042)));
}

Now we configured Spring Data to connect with our Cassandra container. However, we’ll still need to create a keyspace.

2.4. Creating a Keyspace

As the last step before creating any tables in Cassandra, we’ll need to create a keyspace:

private static void createKeyspace(Cluster cluster) {
    try (Session session = cluster.connect()) {
        session.execute("CREATE KEYSPACE IF NOT EXISTS " + KEYSPACE_NAME +
          " WITH replication = \n" +
          "{'class':'SimpleStrategy','replication_factor':'1'};");
    }
}

A keyspace in Cassandra is very similar to a database in an RDBMS. It defines how data replicates on nodes in a Cassandra cluster.

3. Spring Data for Cassandra

Spring Data for Apache Cassandra applies core Spring concepts to the development of applications using Cassandra. It provides repositories, query builders, and simple annotations for rich object mapping. Thus, it offers a familiar interface to Spring developers working with different databases.

3.1. Data Access Object

Let’s start by preparing a simple DAO class which we’ll be using later in our integration tests:

@Table
public class Car {

    @PrimaryKey
    private UUID id;
    private String make;
    private String model;
    private int year;

    public Car(UUID id, String make, String model, int year) {
        this.id = id;
        this.make = make;
        this.model = model;
        this.year = year;
    }

    //getters, setters, equals and hashcode
}

The key here is to annotate the class with @Table annotation from the org.springframework.data.cassandra.core.mapping package. In fact, this annotation enables automatic domain object mapping.

3.2. Cassandra Repository

Spring Data makes it very simple to create a repository for our DAO. To begin with, we’ll need to enable Cassandra repositories in our Spring Boot main class:

@SpringBootApplication
@EnableCassandraRepositories(basePackages = "org.baeldung.springcassandra.repository")
public class SpringCassandraApplication {}

Then, we simply need to create an interface that extends the CassandraRepository:

@Repository
public interface CarRepository extends CassandraRepository<Car, UUID> {}

Before starting with the integration tests, we’ll need to define two additional properties:

spring.data.cassandra.local-datacenter=datacenter1
spring.data.cassandra.schema-action=create_if_not_exists

The first property defines the default local data center name. The second one will ensure that Spring Data automatically creates the required database tables for us. We should note that this setting shouldn’t be used in production systems.

Since we are using Testcontainers, we don’t need to worry about dropping the tables once the tests are finished. A new container will be started for us every time we run our tests.

4. Integration Tests

Now that have our Cassandra container, a simple DAO class, and a Spring Data repository set up, we are ready to start writing integration tests.

4.1. Saving Record Test

Let’s start by testing the insertion of a new record into the Cassandra database:

@Test
void givenValidCarRecord_whenSavingIt_thenRecordIsSaved() {
    UUID carId = UUIDs.timeBased();
    Car newCar = new Car(carId, "Nissan", "Qashqai", 2018);

    carRepository.save(newCar);

    List<Car> savedCars = carRepository.findAllById(List.of(carId));
    assertThat(savedCars.get(0)).isEqualTo(newCar);
}

4.2. Updating Record Test

Then, we can write a similar test for updating an existing database record:

@Test
void givenExistingCarRecord_whenUpdatingIt_thenRecordIsUpdated() {
    UUID carId = UUIDs.timeBased();
    Car existingCar = carRepository.save(new Car(carId, "Nissan", "Qashqai", 2018));

    existingCar.setModel("X-Trail");
    carRepository.save(existingCar);

    List<Car> savedCars = carRepository.findAllById(List.of(carId));
    assertThat(savedCars.get(0).getModel()).isEqualTo("X-Trail");
}

4.3. Deleting Record Test

Finally, let’s write a test for deleting an existing database record:

@Test
void givenExistingCarRecord_whenDeletingIt_thenRecordIsDeleted() {
    UUID carId = UUIDs.timeBased();
    Car existingCar = carRepository.save(new Car(carId, "Nissan", "Qashqai", 2018));

    carRepository.delete(existingCar);

    List<Car> savedCars = carRepository.findAllById(List.of(carId));
    assertThat(savedCars.isEmpty()).isTrue();
}

5. Shared Container Instance

Most of the time, when working with integration tests, we would like to reuse the same database instance across multiple tests. We can share the same container instance by making use of multiple nested test classes:

@Testcontainers
@SpringBootTest
class CassandraNestedIntegrationTest {

    private static final String KEYSPACE_NAME = "test";

    @Container
    private static final CassandraContainer<?> cassandra 
      = new CassandraContainer<>("cassandra:3.11.2").withExposedPorts(9042);

    // Set connection properties and create keyspace

    @Nested
    class ApplicationContextIntegrationTest {
        @Test
        void givenCassandraContainer_whenSpringContextIsBootstrapped_thenContainerIsRunningWithNoExceptions() {
            assertThat(cassandra.isRunning()).isTrue();
        }
    }

    @Nested
    class CarRepositoryIntegrationTest {

        @Autowired
        private CarRepository carRepository;

        @Test
        void givenValidCarRecord_whenSavingIt_thenRecordIsSaved() {
            UUID carId = UUIDs.timeBased();
            Car newCar = new Car(carId, "Nissan", "Qashqai", 2018);

            carRepository.save(newCar);

            List<Car> savedCars = carRepository.findAllById(List.of(carId));
            assertThat(savedCars.get(0)).isEqualTo(newCar);
        }

        // Tests for update and delete
    }
}

Since Docker containers take time to start up, a shared container instance between multiple nested test classes will ensure faster execution. We should note, however, that this shared instance won’t be automatically cleared between tests.

6. Conclusion

In this article, we explored using a Cassandra container for testing a Spring Boot application that uses a Cassandra database.

In the examples, we covered setting up a dockerized Cassandra container instance, overriding test properties, creating a keyspace, a DAO class, and a Cassandra repository interface.

We saw how to write integration tests that make use of a Cassandra container. Thus our example tests required no mocking. Finally, we saw how to reuse the same container instance across multiple nested tests classes.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

eBook Jackson – NPI EA – 3 (cat = Jackson)