SpringTechnology

Unit Tests for Spring Data JDBC Repositories

A Unit Testing Guide for Spring Data JDBC Repositories and Entities. Covers examples of using TestNG or JUnit to unit test Spring Data JDBC.

Overview

Unit Tests are an important aspect of Software Component Development. They ensure that various individual components or units of an application behave as per the specification.

In this tutorial we will cover, how to write Unit Tests for Spring Data JDBC entities and Repositories. We will write tests using TestNG and then with JUnit.

Repository & Entity Bean

Before we begin writing our Unit Tests, let’s have a look at the entity bean and the repository that we will test.

Entity Bean

The entity has a few basic fields and an @Id Field. We are using Lombok to generate an All Argument Constructor and standard getter and setter methods. However, these are not required in order to persist it as an entity.

package com.amitph.spring.tutorials.springdatajdbc.repo;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.data.annotation.Id;

@Data
@AllArgsConstructor
public class Student {
    @Id
    private Long studentId;
    private String firstName;
    private String lastName;
    private Integer year;
}

Repository

The repository interface is extending from CrudRepository, that provides basic DB operations via predefined query methods. We have added two custom query methods to the interface.

package com.amitph.spring.tutorials.springdatajdbc.repo;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface StudentRepository extends CrudRepository<Student, Long> {
    List<Student> findByLastName(@Param("lName") String lastName);

    List<Student> findByLastNameIgnoreCase(@Param("lName") String lastName);
}

Our demo application is a Spring Boot application that you can refer from Introduction to Spring Data JDBC Tutorial.

Unit Tests Setup

For the unit test purpose, we will use H2 Database, which is an in-memory database. When we add h2 dependency in a Spring Boot Project, it automatically configures the database for us.

H2 Database dependency

Make sure, you add the latest version of the database.

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>

We also need to setup database table into the H2 database. To do that, we can use liquibase or data.sql.

In this example, we are using a liquibase script to populate the table on application startup. This is our application-test.properties file configures the liquibase changelog file path.

application-test.yml

spring:
  liquibase:
    change-log: classpath:db/liquibase-changelog.xml

Note that, we are using separate Spring Profile for tests. Because of this our applications main application.yml file can use a different database, while the unit tests can run on H2 Database.

Spring Data JDBC TestNG Tests

In order to use TestNG we need to add its dependency into our project.

<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>

Next, we will create a Test class that extends AbstractTransactionalTsetNGContextTests class. Also, we use @DataJdbcTest annotation which is responsible for taking care of initialising JdbcTemplate and repository, which internally uses JdbcTemplate.

Also note that we are using test as our active profile.

@DataJdbcTest
@ActiveProfiles("test")
public class StudentRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {

    @Autowired
    StudentRepository repository;

    @Test
    public void testFindByLastName() {
        List<Student> expectedList = entities()
                .map(repository::save)
                .filter(student -> student.getLastName().equals("Stark"))
                .collect(Collectors.toList());

        List<Student> actualList = repository.findByLastName("Stark");
        Assert.assertEquals(actualList, expectedList);
    }

    @Test
    public void testFindByLastNameIgnoreCase() {
        List<Student> expectedList = entities()
                .map(repository::save)
                .filter(student -> student.getLastName().equalsIgnoreCase("Stark"))
                .collect(Collectors.toList());

        List<Student> actualList = repository.findByLastNameIgnoreCase("Stark");
        Assert.assertEquals(actualList, expectedList);
    }

    private Stream<Student> entities() {
        return Stream.of(
                new Student(null, "Arya", "Stark", 2023),
                new Student(null, "Jon", "Snow", 2023),
                new Student(null, "Rob", "Stark", 2023),
                new Student(null, "Ned", "stark", 2023)
        );
    }
}

First, we are creating a stream of dummy entities and inserting them into the in-memory database using repository.save() method. Then for each of the returned entities, we apply the same filter which is expected from the actual method. We then collect the stream results into a list of expected elements. Finally, if the expected and actual list matches, our tests pass.

Note: For this example we are using repository to insert the dummy records. Alternatively, you can use JdbcTemplate to do that. You will have to autowire @JdbcTemplate into the test.

@Autowired
JdbcTemplate testJdbcTemplate;

Spring Data JDBC JUnit Tests

In order to run JUnit tests, we can follow the same setup. We will add JUnit dependency.

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>{version}</version>
    <scope>test</scope>
</dependency>

In order to launch the spring context, we need to specify @RunWith annotation.

@RunWith(SpringRunner.class)

Next, is the example of JUnit Tests for the Student Repository.

@RunWith(SpringRunner.class)
@DataJdbcTest
@ActiveProfiles("test")
public class StudentRepositoryTest {

    @Autowired
    StudentRepository repository;

    @Test
    public void testFindByLastName() {
        List<Student> expectedList = entities()
                .map(repository::save)
                .filter(student -> student.getLastName().equals("Stark"))
                .collect(Collectors.toList());

        List<Student> actualList = repository.findByLastName("Stark");

        Assert.assertEquals(expectedList, actualList);
    }

    @Test
    public void testFindByLastNameIgnoreCase() {
        List<Student> expectedList = entities()
                .map(repository::save)
                .filter(student -> student.getLastName().equalsIgnoreCase("Stark"))
                .collect(Collectors.toList());

        List<Student> actualList = repository.findByLastNameIgnoreCase("Stark");
        Assert.assertEquals(expectedList, actualList);
    }

    private Stream<Student> entities() {
        return Stream.of(
                new Student(null, "Arya", "Stark", 2023),
                new Student(null, "Jon", "Snow", 2023),
                new Student(null, "Rob", "Stark", 2023),
                new Student(null, "Ned", "stark", 2023)
        );
    }
}

Summary

In this detailed tutorial we learned How to Write Unit tests for Spring Data JDBC Repository. We covered a basic setup that is required for writing Unit Tests. Then we wrote our unit tests using TestNG and with JUnit.

Visit Spring Tutorials to learn more about Spring and Spring Boot. For the full source code visit github.