# data-jpa-testcontainers Companion module for [`@DataJpaTest` with Testcontainers `@ServiceConnection` on Spring Boot 4.1](https://ankurm.com/) on ankurm.com. ## What this is Six JUnit 5 test classes against one JPA repository (`Product`), each isolating one fact about what `@DataJpaTest`'s default embedded-database substitution actually does, what `@ServiceConnection` wires in its place, and what the defaults do run that you might not expect (Flyway migrations, as it turns out, are one of them). No `docs/NN-topic.md` chapters — everything beyond what fits in the post itself is in the Javadoc on these six test classes and in the captured transcripts below. **Correction, made before this module was published:** an earlier draft of two of these classes asserted that `@DataJpaTest` never runs Flyway or Liquibase migrations, on the strength of reading its four documented meta-annotations' `.imports` manifests and finding no mention of either tool. That reading was accurate and incomplete — see `FlywayRunsByDefaultTest`'s Javadoc and `docs/output/06-autoconfigurejdbc-meta-annotation-javap.txt` for the fifth, undocumented-for-this-slice meta-annotation that actually wires them in. The two test classes below that carried the wrong premise (`FlywayDoesNotRunUnderPlainDataJpaTestTest`, `FlywayRunsWhenExplicitlyImportedTest`) were replaced, not patched, with `FlywayRunsByDefaultTest` and `ExplicitFlywayImportIsRedundantTest`. **This module was built and tested in a sandbox with no Docker daemon available.** Five of the six test classes run and pass (or cleanly skip) without one. The sixth demonstrates, on purpose, the real failure you get from the one case that genuinely needs a container. See the versions table and the test table below for exactly which is which. ## Versions | Dependency | Version | Verified against | |---|---|---| | Spring Boot | 4.1.1 | `spring-boot-dependencies-4.1.1.pom` | | Testcontainers | 2.0.5 | same BOM; `testcontainers-bom-2.0.5.pom` | | Flyway | 12.4.0 | same BOM | | Hibernate ORM | 7.4.5.Final | runtime log, this module's own test run | | H2 | 2.4.240 | runtime log, this module's own test run | | JDK | 25 (Temurin) | `java -version`, this module's own build | ## Quickstart ```bash mvn test # 9 tests run; 1 skips cleanly mvn test -Dtest=ServiceConnectionWithoutGuardFailsToStartTest # the one deliberate failure ``` ## Test classes | Class | What it proves | Needs Docker | Outcome here | |---|---|---|---| | `DefaultReplacementTest` | Plain `@DataJpaTest` substitutes an embedded H2 DataSource, and each test method is rolled back independently of execution order | No | Pass | | `FlywayRunsByDefaultTest` | A plain `@DataJpaTest`, with flyway-core and `spring-boot-starter-flyway` on the (test) classpath, runs the real Flyway migration by default — no `@ImportAutoConfiguration` needed, because `@AutoConfigureJdbc` is itself meta-annotated with `@AutoConfigureDataSourceInitialization`, which merges contributions from every jar on the classpath that ships one | No | Pass | | `ExplicitFlywayImportIsRedundantTest` | Explicitly re-adding `@ImportAutoConfiguration(FlywayAutoConfiguration.class)` — the old advice for the (incorrect) premise above — changes nothing: still exactly one `flyway` bean, still exactly one applied migration | No | Pass | | `NoSubstitutionStillSilentlyUsesH2Test` | `@AutoConfigureTestDatabase(replace = Replace.NONE)` alone is not a guarantee of a real connection — with nothing else configured, ordinary `DataSourceAutoConfiguration` still silently hands you embedded H2 | No | Pass | | `ServiceConnectionSkipsCleanlyTest` | The intended shape: `@ServiceConnection` + `@Container` + `replace = Replace.NONE`, guarded by Testcontainers 2.0's new `@EnabledIfDockerAvailable` | Yes (guarded) | Skipped | | `ServiceConnectionWithoutGuardFailsToStartTest` | The same class, minus the guard | Yes (unguarded) | **Fails — on purpose.** Excluded from `mvn test` by name in `pom.xml`; run it explicitly | ## Captured output | File | Contents | |---|---| | `docs/output/00-full-test-run.txt` | `mvn clean test` — 9 tests, 1 skip, build green | | `docs/output/01-postgresqlcontainer-relocation-javap.txt` | `javap` proof that `org.testcontainers.postgresql.PostgreSQLContainer` (2.0.5's new home) and the deprecated `org.testcontainers.containers.PostgreSQLContainer` shim live in the *same* jar, and that the old class alone keeps the self-referential `` generic | | `docs/output/02-serviceconnection-unaffected-javap.txt` | `javap` proof that `JdbcContainerConnectionDetailsFactory` is typed against `org.testcontainers.containers.JdbcDatabaseContainer` — unmoved by the 2.0 package split, which is why `@ServiceConnection` needed no changes | | `docs/output/04-service-connection-without-guard-fails.txt` | The real `ContainerFetchException` / `IllegalStateException` from trying to start a Postgres container with no Docker daemon present, and no guard against that | | `docs/output/05-service-connection-skips-cleanly.txt` | The same absence of Docker, this time behind `@EnabledIfDockerAvailable` — one line, `Skipped: 1`, no failure | | `docs/output/06-autoconfigurejdbc-meta-annotation-javap.txt` | `javap` proof that `AutoConfigureJdbc.class` is meta-annotated with `@AutoConfigureDataSourceInitialization`, plus the matching `META-INF/spring/...AutoConfigureDataSourceInitialization.imports` file contents from both `spring-boot-jdbc-test` and `spring-boot-flyway` — the actual mechanism behind `FlywayRunsByDefaultTest` | ## What's sourced from code, not run here Two things this article discusses are backed by reading Spring Boot's and Testcontainers' own class files and import manifests rather than by a run in this sandbox, and are called out as such in the post itself: what a *successful* real-Postgres run under `@ServiceConnection` would actually return once a Docker daemon is present (the wiring is verified; the live round trip is not), and Testcontainers' reusable-container feature (`.withReuse(true)` plus `~/.testcontainers.properties`), which has nothing to do with Docker availability but was out of scope for a module built in one sitting.