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 essential aspect of Software Component Development. They ensure that various individual components or units of an application behave as per the specification.

This tutorial covers writing 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 look at the entity bean and the Repository we will test.

Creating an Entity Bean
The entity has a few basic fields and an @Id Field. We use Lombok to generate an all-argument Constructor and standard getter and setter methods.

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;
}Code language: Java (java)

Creating a Repository
The repository interface is extended from the CrudRepository, which provides basic database 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);
}Code language: Java (java)

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

Unit Tests Setup

We will use H2 Database, an in-memory database for the Unit Tests. When we add an H2 dependency in a Spring Boot Project, it automatically configures the database for us.

H2 Database dependency
Make sure to add the latest version of the database.

<dependency>
  <groupId>com.h2database</groupId>
  <artifactId>h2</artifactId>
  <version>{version}</version>
  <scope>test</scope>
</dependency>Code language: HTML, XML (xml)

We also need to set up a database table in the H2 database. To do that, we can use liquibase or data.sql. In this example, we use a liquibase script to populate the table on application startup.

application-test.yml

spring:
  liquibase:
    change-log: classpath:db/liquibase-changelog.xmlCode language: YAML (yaml)

Spring Data JDBC with TestNG Unit Tests

To use TestNG, we need to add its dependency to our project.

<dependency>
  <groupId>org.testng</groupId>
  <artifactId>testng</artifactId>
  <version>{version}</version>
  <scope>test</scope>
</dependency>Code language: HTML, XML (xml)

Next, we will create a Test class that extends AbstractTransactionalTsetNGContextTests class. Also, we use @DataJdbcTest annotation, which is responsible for initializing the JdbcTemplate and the Repository, which internally uses the JdbcTemplate.

Also, note that we use the ‘test‘ as our Spring Boot 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"))
        .toLost();

    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"))
        .toLost();

    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)
    );
  }
}Code language: Java (java)

First, we create a stream of dummy entities and insert them into the in-memory database using the save() method of the Repository interface. 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 the expected elements. Finally, we assert that the expected and the actual Lists match.

Note: We use the Repository to insert the dummy records for this example. Alternatively, you can use JdbcTemplate to do that. You will have to auto-wire a JdbcTemplate instance into the test.

@Autowired
JdbcTemplate testJdbcTemplate;Code language: Java (java)

Spring Data JDBC with JUnit Tests

To run the 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>Code language: HTML, XML (xml)

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

@RunWith(SpringRunner.class)Code language: Java (java)

The following is an 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"))
        .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"))
        .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)
    );
  }
}Code language: Java (java)

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 JUnit.

For the complete source code of the examples, visit our GitHub Repository.