1. Add Dependencies
In pom.xml
(for Maven) or build.gradle
(for Gradle), add the following:
Maven:
<dependencies>
<!-- Spring Boot starter for JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- PostgreSQL driver -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Testcontainers dependencies -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
2. Create a Simple Entity and Repository
// User.java
package com.example.demo;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// getters and setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
// UserRepository.java
package com.example.demo;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository<User, Long> {
}
3. Configure Testcontainers for Integration Test
// UserRepositoryTest.java
package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
@Testcontainers
@DataJpaTest
public class UserRepositoryTest {
@Container
static PostgreSQLContainer<?> postgresContainer = new PostgreSQLContainer<>("postgres:15")
.withDatabaseName("testdb")
.withUsername("user")
.withPassword("password");
@Autowired
private UserRepository userRepository;
// Dynamically inject DB properties to Spring Boot
@DynamicPropertySource
static void setDatasourceProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", postgresContainer::getJdbcUrl);
registry.add("spring.datasource.username", postgresContainer::getUsername);
registry.add("spring.datasource.password", postgresContainer::getPassword);
}
@Test
void testSaveAndFindUser() {
User user = new User();
user.setName("Alice");
userRepository.save(user);
assertThat(userRepository.findAll()).hasSize(1);
}
}
4. How It Works
- Testcontainers starts a PostgreSQL Docker container for the test.
- Spring Boot dynamically connects to this container using
DynamicPropertySource
. - After the test finishes, the container is automatically stopped and removed.
- This ensures isolated, repeatable integration tests without needing a real database installed locally.
5. Notes
- You need Docker installed on your machine for Testcontainers to work.
- You can also use Testcontainers for Kafka, Redis, MySQL, MongoDB, etc.
- Integration tests are slower than unit tests, but they provide real environment validation.