Integration testing of SpringBoot with Postgres using TestContainers

Saurav Kumar
2 min readJun 24, 2023

Testing is an essential part of software development. It helps to ensure that the code is working as expected and that any changes do not introduce new bugs. When testing a Spring Boot application that connects to a PostgreSQL database, it is important to use a real database in the tests. This ensures that the tests are as realistic as possible and that they catch any errors that would occur in production.

Testcontainers is a library that makes it easy to run Docker containers in unit tests. This allows you to use a real PostgreSQL database in your tests without having to set up a separate database server.

To use Testcontainers to test your Spring Boot application, you will need to add the following dependencies to your project:

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.18.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.18.3</version>
<scope>test</scope>
</dependency>

Create PostgresSQLContainer

This test first creates a PostgreSQL container using the postgreSQLContainer variable. The container is configured with the same database name, username, and password.

@Container
private static final PostgreSQLContainer<?> postgreSQLContainer = new PostgreSQLContainer<>("postgres:11.1")
.withDatabaseName("integration-tests-db").withUsername("username").withPassword("password")
.withInitScript("test-data.sql");

Start the PostgreSQLContainer

static {
postgreSQLContainer.start();
}

Add properties for the PostgreSQL

@DynamicPropertySource
static void setProperties(DynamicPropertyRegistry dynamicPropertyRegistry) {
dynamicPropertyRegistry.add("spring.datasource.url", postgreSQLContainer::getJdbcUrl);
dynamicPropertyRegistry.add("spring.datasource.username", postgreSQLContainer::getUsername);
dynamicPropertyRegistry.add("spring.datasource.password", postgreSQLContainer::getPassword);
}

Test cases

Once you have configured Testcontainers, you can start writing your unit tests. Here is an example of a unit test that tests the connection to the PostgreSQL database:

@Test
@Order(value = 1)
void testConnectionToDatabase() {
Assertions.assertNotNull(repository);
}

@Test
@Order(value = 2)
void testAddEmployees() throws Exception {
for (EmployeeRequest employee : employees) {
String emp = objectMapper.writeValueAsString(employee);
mockMvc.perform(
MockMvcRequestBuilders.post("/api/v1/employees").contentType(MediaType.APPLICATION_JSON).content(emp))
.andExpect(status().isCreated());
}
Assertions.assertEquals(5, repository.findAll().size());
}

@Test
@Order(value = 3)
void testGetAllEmployees() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/employees")).andExpect(status().isOk());
Assertions.assertEquals(employees.get(3).getName(), repository.findById(4).get().getName());
}

@Test
@Order(value = 4)
void testGetEmployeeById() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/api/v1/employees/2")).andExpect(status().isOk());
Assertions.assertEquals(employees.get(1).getName(), repository.findById(2).get().getName());
}

@Test
@Order(value = 5)
void testDeleteEmployeeById() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/employees/2")).andExpect(status().isOk());
}

@Test
@Order(value = 6)
void testUpdateEmployee() throws Exception {
Employee employee = Employee.builder().id(3).name("Saurav Kumar Shah").address("India East").build();
String emp = objectMapper.writeValueAsString(employee);
mockMvc.perform(
MockMvcRequestBuilders.put("/api/v1/employees").contentType(MediaType.APPLICATION_JSON).content(emp))
.andExpect(status().isOk());
Assertions.assertEquals(employee.getName(), repository.findById(3).get().getName());
}

@Test
@Order(value = 7)
void testDeleteAllEmployees() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.delete("/api/v1/employees")).andExpect(status().isOk());
Assertions.assertEquals(0, repository.findAll().size());
}

The first test case will check whether the connection to Postgres is successful.

The second test case will add 5 employees to the Postgres database.

The third test case will retrieve all employees from the database.

The fourth test case will retrieve the employee by employee id.

The fifth test case will remove the employee by employee id from the database.

The sixth test case will update the name of the particular employee.

The seventh test case will remove all the employees' records from the Postgres database.

Source code reference

The source code for the examples in this blog can be found on GitHub:

https://github.com/sauravkumarshah/spring-boot-with-postgresql

--

--

Saurav Kumar

I'm a Software engineer at Kantar, skilled in Java and Spring Boot. Passionate about coding and delivering high-quality solutions.