Test containers help you run real databases in temporary containers during tests. This makes tests more reliable and close to real use.
Test containers for database testing in Spring Boot
import org.testcontainers.containers.PostgreSQLContainer; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.AfterAll; public class MyDatabaseTest { static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15") .withDatabaseName("testdb") .withUsername("user") .withPassword("pass"); @BeforeAll public static void startContainer() { postgres.start(); } @AfterAll public static void stopContainer() { postgres.stop(); } // Use postgres.getJdbcUrl(), getUsername(), getPassword() in your tests }
Use the container's JDBC URL and credentials to connect your app during tests.
Containers start before tests and stop after to keep tests isolated.
PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15") .withDatabaseName("testdb") .withUsername("user") .withPassword("pass");
@BeforeAll
public static void startContainer() {
postgres.start();
}@AfterAll
public static void stopContainer() {
postgres.stop();
}String url = postgres.getJdbcUrl();
String user = postgres.getUsername();
String pass = postgres.getPassword();This test starts a PostgreSQL container, creates a table, inserts a message, and checks it. It prints the message to show the test ran.
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.testcontainers.containers.PostgreSQLContainer; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; import static org.junit.jupiter.api.Assertions.assertEquals; public class DatabaseTest { static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:15") .withDatabaseName("testdb") .withUsername("user") .withPassword("pass"); @BeforeAll public static void startContainer() { postgres.start(); } @AfterAll public static void stopContainer() { postgres.stop(); } @Test public void testSimpleQuery() throws Exception { String url = postgres.getJdbcUrl(); String username = postgres.getUsername(); String password = postgres.getPassword(); try (Connection conn = DriverManager.getConnection(url, username, password); Statement stmt = conn.createStatement()) { stmt.execute("CREATE TABLE greetings (message VARCHAR(255));"); stmt.execute("INSERT INTO greetings VALUES ('Hello, Testcontainers!');"); ResultSet rs = stmt.executeQuery("SELECT message FROM greetings;"); if (rs.next()) { String message = rs.getString("message"); assertEquals("Hello, Testcontainers!", message); System.out.println(message); } } } }
Testcontainers require Docker installed and running on your machine.
Use the exact container image version to avoid unexpected changes.
Always stop containers after tests to free resources.
Testcontainers let you run real databases in temporary containers for testing.
They help make integration tests reliable and close to real use.
Start containers before tests and stop them after to keep tests clean and isolated.
Practice
Testcontainers in Spring Boot database testing?Solution
Step 1: Understand Testcontainers role
Testcontainers run real database instances inside temporary containers during tests.Step 2: Compare with other options
Mocking or skipping databases is not what Testcontainers do; they provide real environments temporarily.Final Answer:
To run real database instances in temporary containers for reliable tests -> Option AQuick Check:
Testcontainers purpose = run real temporary databases [OK]
- Confusing Testcontainers with mocking frameworks
- Thinking Testcontainers deploy permanent databases
- Assuming Testcontainers skip database usage
Solution
Step 1: Check correct instantiation and start method
The correct way is to create a static container with generic type and callstart().Step 2: Validate options
static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:latest").start(); uses correct syntax with generic type andstart(). Others use wrong method names or miss generics.Final Answer:
static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:latest").start(); -> Option AQuick Check:
Usestart()with generic type for Testcontainers [OK]
start() method and generic type for containers [OK]- Using .run() or .begin() instead of .start()
- Omitting generic type
- Not declaring container as static when needed
@Testcontainers
class MyRepositoryTest {
@Container
static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:13").withDatabaseName("testdb").withUsername("user").withPassword("pass");
@Autowired
MyRepository repo;
@Test
void testCount() {
long count = repo.count();
System.out.println(count);
}
}What will
System.out.println(count); print if the database is empty?Solution
Step 1: Understand repo.count() behavior
Thecount()method returns the number of records in the repository's table.Step 2: Database is empty so count is zero
Since the database is fresh and empty,count()returns 0, not null or exception.Final Answer:
0 -> Option BQuick Check:
Empty DB count() = 0 [OK]
- Expecting null instead of zero
- Assuming count() throws exception on empty DB
- Confusing count() with find methods
org.testcontainers.containers.ContainerLaunchException. What is the likely cause? @Container
static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:latest");
@Test
void testDb() {
// test code
}Solution
Step 1: Understand ContainerLaunchException meaning
This exception usually means Docker cannot start the container.Step 2: Check common causes
Most common cause is Docker daemon not running or inaccessible to Testcontainers.Final Answer:
Docker is not running or accessible on the test machine -> Option CQuick Check:
ContainerLaunchException = Docker not running [OK]
- Thinking image name is wrong when it is correct
- Trying to start container manually when @Container does it
- Believing Testcontainers don't support PostgreSQL
Solution
Step 1: Understand lifecycle annotations
Using static container with @Container and @Testcontainers on class starts container once before all tests and stops after all.Step 2: Compare other options
Creating container per test or starting/stopping each test is inefficient. Embedded DB is different approach.Final Answer:
Declare a static MySQLContainer with @Container annotation in the test class and use @Testcontainers on the class -> Option DQuick Check:
Static @Container + @Testcontainers = start once before all tests [OK]
- Starting container inside each test method
- Using @BeforeEach/@AfterEach for container lifecycle
- Assuming embedded DB replaces Testcontainers
Ready to prove it?
Pass the test and this pattern moves unknown
