Files
spring-boot-demo/data-jpa-testcontainers/pom.xml
T
Claude 4370ac7fdf Correct post #45: Flyway and Liquibase DO run under @DataJpaTest by default
The previous commit's FlywayDoesNotRunUnderPlainDataJpaTestTest and
FlywayRunsWhenExplicitlyImportedTest rested on a false premise: that none of
@DataJpaTest's four documented meta-annotations import FlywayAutoConfiguration,
so migrations never run under the slice. That reading of the four .imports
manifests is accurate but incomplete. @AutoConfigureJdbc is itself
meta-annotated with @AutoConfigureDataSourceInitialization (new in Boot 4.0),
and Spring's ImportAutoConfigurationImportSelector walks the full
meta-annotation tree transitively. That fifth annotation's own .imports
resource is loaded via ClassLoader.getResources(), which merges same-named
files from every jar on the classpath -- spring-boot-jdbc-test,
spring-boot-flyway and spring-boot-liquibase each ship one at the identical
path, contributing DataSourceInitializationAutoConfiguration,
FlywayAutoConfiguration and LiquibaseAutoConfiguration respectively.

Replaced the two wrong-premise test classes with FlywayRunsByDefaultTest
(proves the bean is present and the migration actually ran) and
ExplicitFlywayImportIsRedundantTest (proves the old "add the import yourself"
advice is harmless but unnecessary on Boot 4.1). Added javap/unzip evidence
for the new mechanism to docs/output, re-captured the full test run (9 tests,
1 clean skip), corrected README's test table, and closed a second,
unrelated gap: the unzip -l listing quoted in the @ServiceConnection section
had no matching captured transcript -- it does now.
2026-10-08 12:35:04 +00:00

150 lines
6.8 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.1</version>
<relativePath/>
</parent>
<groupId>com.ankurm</groupId>
<artifactId>data-jpa-testcontainers</artifactId>
<version>1.0.0</version>
<name>data-jpa-testcontainers</name>
<description>@DataJpaTest with Testcontainers @ServiceConnection on Spring Boot 4.1.1 / Testcontainers 2.0.5:
what the default embedded-database substitution actually does, what @ServiceConnection wires in its
place, and what each one looks like when something is missing.</description>
<packaging>jar</packaging>
<properties>
<java.version>25</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-core</artifactId>
</dependency>
<!-- Flyway 12 split its database-specific parsers out of flyway-core (confirmed in the
db-migrations-flyway-liquibase module's findings). This repo's migration is run twice in
this article: once for real against H2 (no extra dependency needed, H2 support is built
into flyway-core) and once, in the real-Postgres test classes, against whatever
PostgreSQLContainer provides — which needs this dialect module on the classpath even
though that test class cannot start a container in this sandbox. -->
<dependency>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-database-postgresql</artifactId>
</dependency>
<!-- flyway-core on the classpath is NOT enough to get FlywayAutoConfiguration — that class
lives in its own starter, a further instance of Boot 4's per-technology module split
(confirmed by comparing against the db-migrations-flyway-liquibase module, which needs the
exact same starter). This is what actually makes Flyway run under @DataJpaTest by default
in this module: @AutoConfigureJdbc's @AutoConfigureDataSourceInitialization meta-annotation
merges a META-INF/spring/...AutoConfigureDataSourceInitialization.imports file from every
jar that ships one, and spring-boot-flyway (pulled in by this starter) is one of them —
confirmed with javap and unzip, see FlywayRunsByDefaultTest's Javadoc. Test scope only:
this article's main app never runs Flyway itself outside the test slice. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-flyway</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- @DataJpaTest itself: relocated out of spring-boot-test-autoconfigure in Boot 4.1 into its
own module. Confirmed by unzipping this jar: the only class in it is DataJpaTest plus its
bootstrapper and type-exclude filter — TestEntityManager and AutoConfigureTestDatabase are
NOT in here, they come in transitively from the two dependencies below. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-data-jpa-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Pulled in transitively by spring-boot-data-jpa-test above (spring-boot-jpa-test for
TestEntityManager, spring-boot-jdbc-test for AutoConfigureTestDatabase/TestDatabaseAutoConfiguration)
— listed explicitly here only so the module table in the README has something to point at;
removing these two lines changes nothing on the classpath. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-jpa-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-jdbc-test</artifactId>
<scope>test</scope>
</dependency>
<!-- @ServiceConnection itself — unaffected by the Testcontainers 2.0 package moves below,
because it is typed against org.testcontainers.containers.JdbcDatabaseContainer, which did
not move. -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<!-- Testcontainers 2.0.5. PostgreSQLContainer lives at org.testcontainers.postgresql in this
version; org.testcontainers.containers.PostgreSQLContainer still exists as a working
@Deprecated subclass, in this SAME jar (confirmed with `unzip -l`: both classes are inside
testcontainers-postgresql-2.0.5.jar, not split across two artifacts). -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-postgresql</artifactId>
<scope>test</scope>
</dependency>
<!-- The JUnit 5 extension's artifact was renamed from junit-jupiter to
testcontainers-junit-jupiter in 2.0; its package, org.testcontainers.junit.jupiter, did not
change. This version also ships a new @EnabledIfDockerAvailable condition, used below. -->
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>data-jpa-testcontainers</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!-- This class exists to demonstrate a real startup FAILURE on purpose: a container with
no guard against a missing Docker daemon. It is run individually with
`mvn test -Dtest=ServiceConnectionWithoutGuardFailsToStartTest` to capture that
failure for docs/output — excluded here so the module's default `mvn test` build
stays green. -->
<excludes>
<exclude>**/ServiceConnectionWithoutGuardFailsToStartTest.java</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>