Ops, Config & SecurityESSENTIAL7 min deep dive

Testing Strategy: The Modern Testing Pyramid

#Testcontainers#Integration Tests#Unit Tests#Mocking#E2E Testing

The 3-Line Engineering Rule

1. THE RULE

Build a balanced testing pyramid: fast unit tests for domain logic, containerized integration tests (Testcontainers) for data access, and selective E2E tests.

2. WHY IT MATTERS

Relying solely on unit tests with mocked databases creates a false sense of security; tests pass locally, but fail in production on real SQL dialect differences.

3. PRODUCTION FIX

Test business rules in pure unit tests without Spring context (sub-millisecond). Test real queries against real PostgreSQL/Redis instances using Testcontainers in CI.

Architectural Blueprint & Sequence

Hover over nodes to inspect state transitions
THE PRAGMATIC TESTING PYRAMIDSCRIBBLE BLUEPRINT
Ratio of tests, execution speed, and fidelity across testing layers
#1
Top 5 User Flows

10% E2E Smoke Tests

Playwright / Cypress on staging (Slow)

#2
High Fidelity

20% Integration Tests

Testcontainers (Real Postgres & Kafka)

#3
Instant Feedback

70% Pure Unit Tests

Pure domain logic & mockito (Sub-second)

Execution Sequence & Transitions
70% Pure Unit Tests20% Integration Tests[verify contracts]
20% Integration Tests10% E2E Smoke Tests[verify end-to-end journey]

Key Engineering Takeaways

  • Never use H2 in-memory DB to test PostgreSQL-specific features (JSONB, window functions, locking).
  • Keep unit tests independent of external frameworks for lightning-fast feedback.
  • Use Testcontainers to spin up real Dockerized databases and Kafka in integration tests.
  • Reserve expensive end-to-end (E2E) browser tests for top 5 critical user journeys.

The Problem & Production Reality

A brittle test suite slows down engineering velocity. When developers wait 45 minutes for E2E tests that randomly fail due to network timeouts, they stop running tests. A healthy testing strategy gives high confidence with minimal execution time.

Anti-Pattern: In-Memory H2 Mismatch & Heavy Mocking

Testing PostgreSQL queries against an in-memory H2 database. H2 ignores locking semantics, JSONB operators, and Postgres-specific constraints.

ANTI-PATTERN EXAMPLE (JAVA)
// ❌ ANTI-PATTERN: Test passes on H2, fails on production Postgres!
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.ANY) // Uses H2 in-memory
class OrderRepoTest {
    @Test
    void testLocking() {
        // H2 completely ignores SELECT FOR UPDATE SKIP LOCKED
        // Test passes, but deadlocks in production under concurrent traffic!
    }
}

Production Pattern: Real Database Testing with Testcontainers

Spin up an authentic PostgreSQL Docker container automatically during JUnit test execution.

PRODUCTION-READY CODE (JAVA)
// ✅ PRODUCTION PATTERN: Testcontainers for 100% Real PostgreSQL Fidelity
@SpringBootTest
@Testcontainers
class OrderRepositoryIntegrationTest {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine")
        .withDatabaseName("testdb")
        .withUsername("test")
        .withPassword("test");

    @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);
    }

    @Autowired
    private OrderRepository orderRepo;

    @Test
    void testConcurrentInventoryDeduction() {
        // Tests real PostgreSQL row locking and constraint behavior
        int updated = orderRepo.atomicDeductStock("prod_1", 1);
        assertThat(updated).isEqualTo(1);
    }
}

Trade-off Analysis & Staff Recommendations

AspectPros / StrengthsCons / HazardsStaff Recommendation
Testcontainers vs In-Memory Mocks100% fidelity: tests exact SQL dialects, triggers, constraints, and indexes.Takes 5-10 seconds to pull and boot Docker containers on initial test run.Use Testcontainers with reusable mode enabled (`.withReuse(true)`) in local dev.
Mocking Third-Party APIsWireMock allows simulating network delays, 500 errors, and malformed responses.Mocks can drift if the external partner changes their API without notice.Use WireMock for integration test suites; complement with consumer-driven contract tests (Pact).

PR Code Review Checklist (Click to verify)