LS Price Increase Launch

The Price of all “Learn Spring” course packages will increase by $40 on next Friday:

>> GET ACCESS NOW
Cassandra Top
Explore Cassandra in the DataStax Cloud – Astra – using the monthly free credits.

1. Overview

Generally, we use Spring's auto-configuration system such as @SpringBootTest for testing Spring Boot applications. But this results in lots of imports of auto-configured components.

However, it always helps to load only the required parts to test a slice of the application. For this reason, Spring Boot provides many annotations for slice testing. Above all, each of these Spring annotations loads a very limited set of auto-configured components that are required for a particular layer.

In this tutorial, we'll focus on testing a Cassandra database slice of a Spring Boot application in order to learn about @DataCassandraTest annotation provided by Spring.

Additionally, we'll look at a small Cassandra-based Spring Boot application in action. 

And, if you’re running Cassandra in production, you can definitely cut out the complexity of running and maintaining your own server and use the Astra database instead, which is a cloud-based database built on Apache Cassandra.

2. Maven Dependencies

To use the @DataCassandraTest annotation in our Cassandra Spring Boot application, we have to add the spring-boot-starter-test dependency:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-test</artifactId>
    <version>2.5.3</version>
    <scope>test</scope>
</dependency>

Spring's spring-boot-test-autoconfigure is part of the spring-boot-starter-test library, and it contains lots of auto-configuration components for testing different slices of an application.

Generally, this test annotation has a pattern of @XXXTest.

@DataCassandraTest annotation imports the following Spring data auto-configuration components:

  • CacheAutoConfiguration
  • CassandraAutoConfiguration
  • CassandraDataAutoConfiguration
  • CassandraReactiveDataAutoConfiguration
  • CassandraReactiveRepositoriesAutoConfiguration
  • CassandraRepositoriesAutoConfiguration

3. Example Cassandra Spring Boot Application

To illustrate these concepts, we have a simple Spring Boot web application whose main domain is vehicle inventory.

To keep it simple, this application provides basic CRUD operations of the inventory data.

3.1. Cassandra Maven Dependency

Spring provides the spring-boot-starter-data-cassandra module for Cassandra data:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-cassandra</artifactId>
    <version>2.5.3</version>
</dependency>

We also need the dependency on the Datastax Cassandra's java-driver-core to enable cluster connectivity and request execution:

<dependency> 
    <groupId>com.datastax.oss</groupId> 
    <artifactId>java-driver-core</artifactId> 
    <version>4.13.0</version> 
</dependency>

3.2. Cassandra Configuration

Here our CassandraConfig class extends Spring's AbstractCassandraConfiguration, which is the base class for Spring Data Cassandra configuration.

This spring class is used to configure the Cassandra client application with CqlSession to connect to the Cassandra cluster.

Additionally, we can configure the keyspace name and cluster host:

@Configuration
public class CassandraConfig extends AbstractCassandraConfiguration {

    @Override
    protected String getKeyspaceName() {
        return "inventory";
    }

    @Override
    public String getContactPoints() {
        return "localhost";
    }

    @Override
    protected String getLocalDataCenter() {
         return "datacenter1";
    }
}

4. Data Model

The following Cassandra Query Language (CQL) creates Cassandra keyspace by name inventory:

CREATE KEYSPACE inventory
WITH replication = {
    'class' : 'NetworkTopologyStrategy',
    'datacenter1' : 3
};

And this CQL creates a Cassandra table by name vehicles in inventory keyspace:

use inventory;

CREATE TABLE vehicles (
   vin text PRIMARY KEY,
   year int,
   make varchar,
   model varchar
);

5. @DataCassandraTest Usage

Let's look at how we can use @DataCassandraTest in unit tests to test the data layer of the application.

The @DataCassandraTest annotation imports the required Cassandra auto-configuration modules, which includes scanning @Table and @Repository components. As a result, it makes it possible to @Autowire the Repository class.

However, it does not scan and import the regular @Component and @ConfigurationProperties beans.

Additionally, with JUnit 4, this annotation should be used in combination with @RunWith(SpringRunner.class).

5.1. Integration Test Class

Here is the InventoryServiceIntegrationTest class with the @DataCassandraTest annotation and the repository @Autowired:

@RunWith(SpringRunner.class)
@DataCassandraTest
@Import(CassandraConfig.class)
public class InventoryServiceIntegrationTest {

    @Autowired
    private InventoryRepository repository;

    @Test
    public void givenVehiclesInDBInitially_whenRetrieved_thenReturnAllVehiclesFromDB() {
        List<Vehicle> vehicles = repository.findAllVehicles();

        assertThat(vehicles).isNotNull();
        assertThat(vehicles).isNotEmpty();
    }
}

We’ve also added a simple test method above.

To make it easier to run this test, we’ll use a DockerCompose Test Container, which sets up a three-node Cassandra cluster: 

public class InventoryServiceLiveTest {

    // ...

    public static DockerComposeContainer container =
            new DockerComposeContainer(new File("src/test/resources/compose-test.yml"));

    @BeforeAll
    static void beforeAll() {
        container.start();
    }

    @AfterAll
    static void afterAll() {
        container.stop();
    }
}

You can find the compose-test.yml file in the GitHub project here.

5.2. Repository Class

The example repository class InventoryRepository defines a few custom JPA methods:

@Repository
public interface InventoryRepository extends CrudRepository<Vehicle, String> {

    @Query("select * from vehicles")
    List<Vehicle> findAllVehicles();

    Optional<Vehicle> findByVin(@Param("vin") String vin);

    void deleteByVin(String vin);
}

We’ll  also define a Consistency level of “local-quorum”, which implies a strong consistency, by adding this property to the application.yml file:

spring:
  data:
    cassandra:
      request:
        consistency: local-quorum

6. Other @DataXXXTest Annotations

Following are some of the other similar annotations to test the database layer of any application:

  • @DataJpaTest imports JPA repositories, @Entity classes, etc.
  • @DataJdbcTest imports Spring Data repositories, JdbcTemplate, etc.
  • @DataMongoTest imports Spring Data MongoDB repositories, Mongo templates and @Document classes
  • @DataNeo4jTest imports Spring Data Neo4j repositories, @Node classes
  • @DataRedisTest imports Spring Data Redis repositories, @RedisHash

Please visit the Spring documentation for more test annotations and detailed information.

7. Conclusion

In this article, we learned how @DataCassandraTest annotation loads a few Spring Data Cassandra auto-configuration components. As a result, it avoids loading many unwanted Spring context modules.

As always, the full source code is available over on GitHub.

LS Price Increase Launch

The Price of all “Learn Spring” course packages will increase by $40 on next Friday:

>> GET ACCESS NOW
Generic footer banner
guest
0 Comments
Inline Feedbacks
View all comments