3 In-Memory Database Usage Strategy for Spring Boot Integration Test
Abstract
Having integration test is always a good practice to have when you write your Spring Boot micro-services. Primary objective is to test each functionality of our code without using any mocking framework at integration test stage. There are few options available in open source community to use in-memory database instead of using a real one to facilitate this need.
In this article we are going to look at 3 easy-to-use in-memory database approach for our Spring Boot application testing.
We we will be using Postgres database for this illustration but the same concept can be extended to other supported databases as well.
Setup
Here is the simple project structure of a typical Spring Boot application for micro-service.
The Spring Boot Application Class
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
The Controller Class
@RestController
@RequestMapping("/customer")
@Slf4j
public class CustomerController {
@Autowired
private CustomerService customerService;
@PostMapping
public Customer saveCustomer(@RequestBody Customer customer) {
log.info("Save customers {}", customer);
return customerService.saveCustomer(customer);
}
}
The Service Class
@Service
public class CustomerService {
@Autowired
private CustomerRepository customerRepository;
public Customer saveCustomer(Customer customer) {
return customerRepository.save(customer);
}
}
The Repository Class
@Repository
public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
The Entity Class
@Entity
@SequenceGenerator(name = "customer_generator", sequenceName = "customer_sequence", allocationSize = 1)
@Data
@Builder
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "customer_generator")
@Column(name = "CUSTOMER_ID")
private Long customerId;
@Column(name = "CUSTOMER_NAME")
private String customerName;
}
Option 1 — h2 database
Good old h2 database is the simplest & easiest option among all. We just need to add the following dependency into the pom.xml
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
Let’s add the following to the application-test.properties
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
Now this is our simple Test class
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("test")
class DemoApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
void givenCustomer_whenPostCustomer_thenStatus200() throws Exception {
String request = "{\"customerName\": \"John\"}";
mockMvc.perform(post("/customer")
.contentType(MediaType.APPLICATION_JSON)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.customerId").value("1"));
}
}
Option 2 — Docker Container
This option uses powerful zonky spring-ready framework which internally involves testcontainers to run appropriate docker containers without writing any code.
You need to have Docker installed & running where this test is running.
Add the following dependency into the pom.xml
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-database-spring-test</artifactId>
<version>2.0.1</version>
<scope>test</scope>
</dependency>
Add the following to the application-test.properties
zonky.test.database.postgres.docker.image=postgres:11-alpine
Add the annotation @AutoConfigureEmbeddedDatabase to the test class
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureEmbeddedDatabase
@ActiveProfiles("test")
class DemoApplicationTests {
@Autowired
private MockMvc mockMvc;
@Test
void givenCustomer_whenPostCustomer_thenStatus200() throws Exception {
String request = "{\"customerName\": \"John\"}";
mockMvc.perform(post("/customer")
.contentType(MediaType.APPLICATION_JSON)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.customerId").value("1"));
}
}
Option 3— Embedded Database
This option also uses powerful zonky spring-ready framework which internally involves database-as-a-library and run the appropriate database in-memory.
Add the following dependencies into the pom.xml
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-database-spring-test</artifactId>
<version>2.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.zonky.test</groupId>
<artifactId>embedded-postgres</artifactId>
<version>1.3.0</version>
<scope>test</scope>
</dependency>
Add the following to the application-test.properties
zonky.test.database.provider=ZONKY
Add the annotation @AutoConfigureEmbeddedDatabase to the test class
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureEmbeddedDatabase
@ActiveProfiles("test")
class DemoApplicationTests { @Autowired
private MockMvc mockMvc; @Test
void givenCustomer_whenPostCustomer_thenStatus200() throws Exception {
String request = "{\"customerName\": \"John\"}";
mockMvc.perform(post("/customer")
.contentType(MediaType.APPLICATION_JSON)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.customerId").value("1"));
}
}
Source Code
A working sample code is available here in GitHub repo.