@DataR2dbcTest - Testing Spring Data R2DBC components
In this section, we will learn how to test Data R2DBC components with @DataR2dbcTest in the Spring Boot application.
About @DataR2dbcTest
Instead of bootstrapping the entire application context for every test, @DataR2dbcTest allows us to initialize only the parts of the Application context that are relevant to Data R2DBC components tests.
Regular @Component, @Service or @Controller beans are not scanned when using this annotation.
This approach not only speeds up the testing process but also ensures a focused and efficient testing environment.
This approach is also known as "slicing" the application context.
The annotation supports the following attributes:
- excludeAutoConfiguration: Auto-configuration exclusions that should be applied for this test.
- excludeFilters: beans that would ordinarily be added to the application context can be filtered using a set of exclude filters.
- includeFilters: beans that would otherwise be filtered and added to the application environment using a set of include filters.
- properties: Before the test runs, the properties in the key=value format should be added to the Spring Environment.
- useDefaultFilters: Determines if default filtering should be used with @SpringBootApplication.
Complete Example with @DataR2dbcTest
Next we will create a spring boot Data R2DBC application, create repository layer which contains a query methods and finally we will write test against Real(PostgreSQL) database
Creating a spring boot application
First, open the Spring initializr https://start.spring.io
Then, Provide the Group and Artifact name. We have provided Group name com.knf.dev.demo and Artifact datar2dbctest-annotation-example. Here I selected the Maven project - language Java 17 - Spring Boot 3.2.5, Spring Data R2DBC, Lombok, and PostgreSQL Driver.
Final Project Directory
Complete pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.knf.dev.demo</groupId>
<artifactId>datar2dbctest-annotation-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>datar2dbctest-annotation-example</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yaml
#PostgreSQL configuration
spring:
r2dbc:
url: r2dbc:postgres://localhost:5432/postgres
username: postgres
password: root
Let's create the scripts for testing our application.
Create test-student-schema.sql
DROP table if exists students;
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name VARCHAR(250) NOT NULL,
email VARCHAR(250) NOT NULL,
age INT
);
Create test-student-data.sql
INSERT INTO students (id,name, email, age) VALUES
(101,'Alpha', 'alpha@knf.com', 50),
(102,'Beta', 'beta@knf.com', 40),
(103,'Gama', 'gama@knf.com', 30),
(104,'Pekka', 'pekka@knf.com', 20);
Create Student Entity
Create entity class to represent the students table
package com.knf.dev.demo.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Table;
@Table(name = "students")
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
public class Student {
@Id
private Long id;
private String name;
private String email;
private Integer age;
}
Create Student Repository
package com.knf.dev.demo.repository;
import com.knf.dev.demo.entity.Student;
import org.springframework.data.r2dbc.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Mono;
public interface StudentRepository
extends ReactiveCrudRepository<Student, Long> {
@Query("SELECT * FROM Student WHERE email = $1")
Mono<Student> findStudentByEmail(String email);
}
Driver class
package com.knf.dev.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Datar2dbctestAnnotationExampleApplication {
public static void main(String[] args) {
SpringApplication.run(Datar2dbctestAnnotationExampleApplication.class, args);
}
}
Implementing the Tests
When using JUnit 4, @SpringBootTest annotation should be used in combination with @RunWith(SpringRunner.class). But for this example we are using JUnit 5, there’s no need to add the equivalent @ExtendWith(SpringExtension.class).
package com.knf.dev.demo;
import com.knf.dev.demo.repository.StudentRepository;
import io.r2dbc.spi.ConnectionFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.autoconfigure.data.r2dbc.DataR2dbcTest;
import org.springframework.core.io.Resource;
import org.springframework.r2dbc.connection.init.ScriptUtils;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import static org.junit.jupiter.api.Assertions.assertEquals;
@DataR2dbcTest
public class StudentRepositoryTests {
@Autowired
private StudentRepository studentRepository;
@Autowired
ConnectionFactory connectionFactory;
@BeforeEach
private void setUp(@Value("classpath:/test-student-data.sql")
Resource script1,
@Value("classpath:/test-student-schema.sql")
Resource script2) {
executeScriptBlocking(script2);
executeScriptBlocking(script1);
}
@Test
void findStudentByEmail_ReturnsTheStudent() {
this.studentRepository.findStudentByEmail("alpha@knf.com")
.as(StepVerifier::create)
.consumeNextWith(p ->
assertEquals("Alpha", p.getName()))
.verifyComplete();
}
private void executeScriptBlocking(final Resource sqlScript) {
Mono.from(connectionFactory.create())
.flatMap(connection -> ScriptUtils
.executeSqlScript(connection, sqlScript))
.block();
}
}
Run the test
Or you can run the test using following command:
mvn test -Dtest=StudentRepositoryTests