# Testcontainers JDBC Testing JPA repositories with real databases using Testcontainers. ## Overview Testcontainers provides real database instances in Docker containers for integration testing. More reliable than H2 for production parity. ## PostgreSQL Setup ### Dependencies ```xml org.springframework.boot spring-boot-testcontainers test org.testcontainers testcontainers-postgresql test ``` ### Basic Test ```java @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers class OrderRepositoryPostgresTest { @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18"); @Autowired private OrderRepository orderRepository; @Autowired private TestEntityManager entityManager; } ``` ## MySQL Setup ```xml org.testcontainers testcontainers-mysql test ``` ```java @Container @ServiceConnection static MySQLContainer mysql = new MySQLContainer<>("mysql:8.4"); ``` ## Multiple Databases ```java @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers class MultiDatabaseTest { @Container @ServiceConnection(name = "primary") static PostgreSQLContainer primaryDb = new PostgreSQLContainer<>("postgres:18"); @Container @ServiceConnection(name = "analytics") static PostgreSQLContainer analyticsDb = new PostgreSQLContainer<>("postgres:18"); } ``` ## Container Reuse (Speed Optimization) Add to `~/.testcontainers.properties`: ```properties testcontainers.reuse.enable=true ``` Then enable reuse in code: ```java @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18") .withReuse(true); ``` ## Database Initialization ### With SQL Scripts ```java @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18") .withInitScript("schema.sql"); ``` ### With Flyway ```java @SpringBootTest @Testcontainers @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) class MigrationTest { @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18"); @Autowired private Flyway flyway; @Test void shouldApplyMigrations() { flyway.migrate(); // Test code } } ``` ## Advanced Configuration ### Custom Database/Schema ```java @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18") .withDatabaseName("testdb") .withUsername("testuser") .withPassword("testpass") .withInitScript("init-schema.sql"); ``` ### Wait Strategies ```java @Container static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18") .waitingFor(Wait.forLogMessage(".*database system is ready.*", 1)); ``` ## Test Example ```java @DataJpaTest @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @Testcontainers class OrderRepositoryTest { @Container @ServiceConnection static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18"); @Autowired private OrderRepository orderRepository; @Autowired private TestEntityManager entityManager; @Test void shouldFindOrdersByStatus() { // Given entityManager.persist(new Order("PENDING")); entityManager.persist(new Order("COMPLETED")); entityManager.flush(); // When List pending = orderRepository.findByStatus("PENDING"); // Then assertThat(pending).hasSize(1); assertThat(pending.get(0).getStatus()).isEqualTo("PENDING"); } @Test void shouldSupportPostgresSpecificFeatures() { // Can use Postgres-specific features like: // - JSONB columns // - Array types // - Full-text search } } ``` ## @DynamicPropertySource Alternative If not using @ServiceConnection: ```java @SpringBootTest @Testcontainers class OrderServiceTest { @Container static PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:18"); @DynamicPropertySource static void configureProperties(DynamicPropertyRegistry registry) { registry.add("spring.datasource.url", postgres::getJdbcUrl); registry.add("spring.datasource.username", postgres::getUsername); registry.add("spring.datasource.password", postgres::getPassword); } } ``` ## Supported Databases | Database | Container Class | Maven Artifact | | -------- | --------------- | -------------- | | PostgreSQL | PostgreSQLContainer | testcontainers-postgresql | | MySQL | MySQLContainer | testcontainers-mysql | | MariaDB | MariaDBContainer | testcontainers-mariadb | | SQL Server | MSSQLServerContainer | testcontainers-mssqlserver | | Oracle | OracleContainer | testcontainers-oracle-free | | MongoDB | MongoDBContainer | testcontainers-mongodb | ## Best Practices 1. Use @ServiceConnection when possible (Spring Boot 3.1+) 2. Enable container reuse for faster local builds 3. Use specific versions (postgres:18) not latest 4. Keep container config in static field 5. Use @DataJpaTest with AutoConfigureTestDatabase.Replace.NONE