18 · Testing the complete backend / LESSON 91 OF 102
PostgreSQL integration tests with Testcontainers
A disposable real database catches differences that an in-memory substitute may hide.
Before this lesson: MockMvc, JSON contracts, and security tests
Understand the topic
Testcontainers starts a database container and supplies connection details to the test. Boot service connections can configure supported containers automatically when the corresponding test support is present. Docker or a compatible configured runtime is required in local and CI environments.
Run the same migrations used by the application. Pin a tested image version or digest for reproducible CI and never point tests at production. Container startup overhead is worthwhile for a focused set of integration tests rather than every pure-domain assertion.
EXAMPLE · JAVA
DatabaseIT.java
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.testcontainers.junit.jupiter.*;
import org.testcontainers.postgresql.PostgreSQLContainer;
@SpringBootTest
@Testcontainers
class DatabaseIT {
@Container @ServiceConnection
static PostgreSQLContainer database = new PostgreSQLContainer("postgres:17-alpine");
@Test void contextStartsWithMigrations() {}
}What to expect
For Testcontainers 2.x use testcontainers-postgresql, testcontainers-junit-jupiter, and spring-boot-testcontainers in test scope. Verify the managed version/imports in your generated project; add real persistence assertions beyond this startup smoke test.
YOUR TURN
Put it into practice
- 01Run migrations against a disposable PostgreSQL container.
- 02Add a repository round-trip and a unique-constraint test; execute through Failsafe verify.
- 03Verify: The tests use the production database engine and cannot contact a production URL.
Pass a quiz or complete a lab to check today’s streak. Each lesson counts once per day, including when you review it later.
UNDER THE HOOD
Build the mental model
A disposable real database catches differences that an in-memory substitute may hide.
- 01Testcontainers starts a database container and supplies connection details to the test. Boot service connections can configure supported containers automatically when the corresponding test support is present. Docker or a compatible configured runtime is required in local and CI environments.
- 02Run the same migrations used by the application. Pin a tested image version or digest for reproducible CI and never point tests at production. Container startup overhead is worthwhile for a focused set of integration tests rather than every pure-domain assertion.
- 03Trace the example: For Testcontainers 2.x use testcontainers-postgresql, testcontainers-junit-jupiter, and spring-boot-testcontainers in test scope. Verify the managed version/imports in your generated project; add real persistence assertions beyond this startup smoke test.
A mistake worth avoiding
Integration tests cannot connect because no container runtime is available.
DEBUGGING ROOM
Something broke. Where do you look?
Integration tests cannot connect because no container runtime is available.
Before revealing the diagnosis, write down your first investigation step.
CHECK YOUR UNDERSTANDING
Should integration tests fall back to the production database when Docker is unavailable?
BUILD IT YOURSELF
Run migrations against a disposable PostgreSQL container.
- 1.Run migrations against a disposable PostgreSQL container.
- 2.Add a repository round-trip and a unique-constraint test; execute through Failsafe verify.
- 3.Reproduce this failure, then repair it: Integration tests cannot connect because no container runtime is available.
Acceptance checklist
Lab completion is your self-report. Knowledge checks do not certify project quality.
RETRIEVE IT FROM MEMORY
Should integration tests fall back to the production database when Docker is unavailable?
Revisit this lesson in three days after a successful check or lab.
Ready for the next step?
The tests use the production database engine and cannot contact a production URL.
Reading is separate from passing a knowledge check or completing a lab.