使用@SpringBootTest集成测试时无法初始化PostgreSQL数据库
问题分析与解决方案:Spring Boot集成测试中Testcontainers+Flyway启动失败
问题场景
我使用@SpringBootTest编写集成测试,尝试通过Testcontainers自动启动PostgreSQL数据库,搭配Flyway做数据库迁移,但应用启动失败,报错提示PostgreSQL驱动不识别Testcontainers格式的JDBC URL。
测试基类代码
@SpringBootTest @AutoConfigureMockMvc @Transactional @ActiveProfiles("test") abstract public class IntegrationTest { @Autowired protected MockMvc mvc; }
控制器测试类
class ProductControllerTest extends IntegrationTest { @Test // @Sql("/create-product.sql") void findById() throws Exception { mvc.perform((get("/api/v1/products/{id}", 1))) .andExpect(status().isOk()) .andExpect(jsonPath("$.data.name", equalTo("TV"))); } //... }
测试环境配置(application-test.yml)
spring: datasource: # url: jdbc:postgresql:13.2-alpine://product # url: jdbc:postgresql://localhost:5432/product url: jdbc:tc:postgresql:11:1:///product flyway: enabled: true placeholderReplacement: false baseline-on-migrate: true
报错信息
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:tc:postgresql:11:1:///product 2023-03-20 03:37:26.933 ERROR 26832 --- [ main] SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Driver org.postgresql.Driver claims to not accept jdbcUrl, jdbc:tc:postgresql:11:1:///product
依赖配置(pom.xml)
<dependency> <groupId>org.flywaydb</groupId> <artifactId>flyway-core</artifactId> <version>9.15.2</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>1.17.6</version> <scope>test</scope> </dependency> <!-- Also tried with these --> <!-- <dependency>--> <!-- <groupId>org.testcontainers</groupId>--> <!-- <artifactId>testcontainers-bom</artifactId>--> <!-- <version>1.17.6</version>--> <!-- <type>pom</type>--> <!-- </dependency>--> <!-- <dependency>--> <!-- <groupId>org.testcontainers</groupId>--> <!-- <artifactId>postgresql</artifactId>--> <!-- <version>1.17.6</version>--> <!-- <scope>test</scope>--> <!-- </dependency>-->
问题原因与解决步骤
1. 修正Testcontainers JDBC URL格式
你使用的jdbc:tc:postgresql:11:1:///product格式错误,Testcontainers的PostgreSQL URL正确格式为:jdbc:tc:postgresql:<主版本号>:///<数据库名>
不需要携带补丁号(如11:1),修正后的URL:
spring: datasource: url: jdbc:tc:postgresql:11:///product
2. 完善Testcontainers依赖配置
Testcontainers需要专门的JDBC代理驱动解析jdbc:tc:开头的URL,推荐使用BOM统一管理版本,避免版本冲突:
<dependencyManagement> <dependencies> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers-bom</artifactId> <version>1.17.6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 保留原有依赖 --> <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> </dependencies>
3. 配置Flyway适配Testcontainers
Flyway默认会使用原生PostgreSQL驱动,需要指定其使用Testcontainers的数据源,同时显式指定Testcontainers驱动类:
spring: datasource: url: jdbc:tc:postgresql:11:///product driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver flyway: enabled: true placeholderReplacement: false baseline-on-migrate: true url: ${spring.datasource.url} user: ${spring.datasource.username} password: ${spring.datasource.password}
4. 测试数据初始化方式选择
- 如果Flyway迁移脚本已经包含测试数据,无需使用
@Sql注解; - 如果迁移脚本仅负责建表,可通过
@Sql("/create-product.sql")注解或者在测试类中调用Repository提前插入数据,两种方式均可。
内容的提问来源于stack exchange,提问作者user21431812
相关产品推荐
相关产品推荐

