Add Testcontainers + @DataJpaTest against real PostgreSQL 16 #119

Closed
opened 2026-03-27 18:35:35 +01:00 by marcel · 1 comment
Owner

Problem

The backend test suite has zero integration tests that run against a real PostgreSQL database. The pom.xml includes H2 in test scope, and all controller tests mock the service layer. This means:

  • Flyway migrations are never executed in CI — a broken migration won't be discovered until production
  • JPA queries are never verified against actual PostgreSQL behavior (type coercions, index usage, query planner quirks differ from H2)
  • PostgreSQL-specific features used in this project (UUID primary keys, Flyway versioned migrations) have no test coverage

Why This Matters

H2 is a different database. It silently accepts SQL that PostgreSQL would reject. We have caught this pattern in other projects — mocked/in-memory tests pass, production migration fails. The cost of that discovery is far higher than the cost of fixing this now.

What Needs To Be Done

  1. Add Testcontainers dependencies to pom.xml:
    <dependency>
      <groupId>org.testcontainers</groupId>
      <artifactId>postgresql</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-testcontainers</artifactId>
      <scope>test</scope>
    </dependency>
    
  2. Remove H2 from test dependencies — its presence is a temptation
  3. Add a base @DataJpaTest test class with a shared PostgreSQLContainer via @DynamicPropertySource
  4. Write @DataJpaTest tests for at least DocumentRepository and PersonRepository covering:
    • Basic CRUD
    • Custom query methods
    • Flyway migration runs cleanly from a clean DB (verified implicitly by every test run)
  5. Add a @SpringBootTest smoke test that starts the full application context against the container

Acceptance Criteria

  • CI runs no H2-backed tests — Testcontainers PostgreSQL 16 used everywhere
  • Flyway migrations run and succeed on every CI test run
  • At minimum DocumentRepository and PersonRepository have @DataJpaTest coverage
  • No H2 dependency in pom.xml
## Problem The backend test suite has zero integration tests that run against a real PostgreSQL database. The `pom.xml` includes H2 in test scope, and all controller tests mock the service layer. This means: - Flyway migrations are **never executed in CI** — a broken migration won't be discovered until production - JPA queries are never verified against actual PostgreSQL behavior (type coercions, index usage, query planner quirks differ from H2) - PostgreSQL-specific features used in this project (UUID primary keys, Flyway versioned migrations) have no test coverage ## Why This Matters H2 is a different database. It silently accepts SQL that PostgreSQL would reject. We have caught this pattern in other projects — mocked/in-memory tests pass, production migration fails. The cost of that discovery is far higher than the cost of fixing this now. ## What Needs To Be Done 1. Add Testcontainers dependencies to `pom.xml`: ```xml <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-testcontainers</artifactId> <scope>test</scope> </dependency> ``` 2. Remove H2 from test dependencies — its presence is a temptation 3. Add a base `@DataJpaTest` test class with a shared `PostgreSQLContainer` via `@DynamicPropertySource` 4. Write `@DataJpaTest` tests for at least `DocumentRepository` and `PersonRepository` covering: - Basic CRUD - Custom query methods - Flyway migration runs cleanly from a clean DB (verified implicitly by every test run) 5. Add a `@SpringBootTest` smoke test that starts the full application context against the container ## Acceptance Criteria - [ ] CI runs no H2-backed tests — Testcontainers PostgreSQL 16 used everywhere - [ ] Flyway migrations run and succeed on every CI test run - [ ] At minimum `DocumentRepository` and `PersonRepository` have `@DataJpaTest` coverage - [ ] No H2 dependency in `pom.xml`
marcel added the test label 2026-03-27 18:45:06 +01:00
Author
Owner

Architect review (@mkeller): Most important ticket in this batch — do this first.

H2 in test scope is a genuine liability. Flyway migrations never running in CI will eventually cause a production incident. The concern here is well-founded.

One implementation note: the ticket shows @DynamicPropertySource to wire the container, which is the Spring Boot 3.0 pattern. This project runs Boot 4.0 — use @ServiceConnection instead, it's less ceremony and more idiomatic:

@SpringBootTest
class SmokeTest {
    @Container
    @ServiceConnection
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
}

Also: sequence this before #120 (JaCoCo coverage gate). There is no point enforcing an 80% gate against a mock-heavy test suite. Get real tests in place first, measure the actual baseline, then gate.

**Architect review (@mkeller):** ✅ Most important ticket in this batch — do this first. H2 in test scope is a genuine liability. Flyway migrations never running in CI will eventually cause a production incident. The concern here is well-founded. One implementation note: the ticket shows `@DynamicPropertySource` to wire the container, which is the Spring Boot 3.0 pattern. This project runs Boot 4.0 — use `@ServiceConnection` instead, it's less ceremony and more idiomatic: ```java @SpringBootTest class SmokeTest { @Container @ServiceConnection static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16"); } ``` Also: sequence this before #120 (JaCoCo coverage gate). There is no point enforcing an 80% gate against a mock-heavy test suite. Get real tests in place first, measure the actual baseline, then gate.
Sign in to join this conversation.
No Label test
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#119