You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Liquibase测试数据迁移触发邮箱唯一键冲突,测试启动失败求助

Liquibase预加载测试数据导致Testcontainers启动失败(唯一键冲突)

核心报错信息

Caused by: liquibase.exception.MigrationFailedException: Migration failed for changeset db/changelog/inserts/insert_test_user.yaml::2::Jakub.Kolacz:
 Reason: liquibase.exception.DatabaseException: ERROR: duplicate key value violates unique constraint "user_email_key" Details: Key (email)=(john.doe@example.com) already exists. [Failed SQL: (0) INSERT INTO public.users (id, first_name, last_name, email, password, city, zip_code, street, building_number, flat_number) VALUES ('3', 'John', 'Doe', 'john.doe@example.com', 'password123', 'Warsaw', '00-001', 'Main St', '123', '45A')]

测试目标接口

@PostMapping
public ResponseEntity<UserEntity> createUser(@RequestBody UserDto user) {
    try {
        return ResponseEntity.status(HttpStatus.CREATED).body(userService.save(user));
    } catch (Exception e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(null);
    }
}

使用的技术栈

  • Spock 测试框架
  • Testcontainers(PostgreSQL)模拟测试数据库
  • Liquibase 数据库版本管理工具

运行测试时出现Failed to load ApplicationContext错误,根源是Liquibase执行变更集时触发唯一键冲突,导致应用上下文加载失败。

测试代码

class UserControllerITest extends BaseIntegrationTest {

    @Autowired
    UserRepository userRepository

    def "should return bad request when posted user's email is not unique"() {
    given: "a user and address DTO"
    def addressEntity = new AddressEntity(
            city: "Warsaw",
            zipCode: "00-001",
            street: "Main St",
            buildingNumber: "123",
            flatNumber: "45A"
    )

    def userDto = new UserEntity(
            id: 2L,
            firstName: "John",
            lastName: "Doe",
            email: "john.doe@example.com",
            password: "password123",
            address: addressEntity
    )

    def addressDto2 = new AddressDto(
            city: "Warsaw",
            zipCode: "00-001",
            street: "Main St",
            buildingNumber: "123",
            flatNumber: "45A"
    )

    def userDto2 = new UserDto(
            id: 3L,
            firstName: "John",
            lastName: "Doe",
            email: "john.doe@example.com",
            password: "password123",
            address: addressDto2
    )

    when: "create user endpoint is called"
    //userRepository.save(userDto)
    ResponseEntity response = restTemplate.postForEntity(addressToUseForTests + "/api/users", userDto2, UserDto)

    then: "response is 400 Bad request"
    response.statusCode == HttpStatus.BAD_REQUEST

}

基础集成测试类配置

@Testcontainers
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@TestPropertySource(locations = "classpath:application-test.properties")
abstract class BaseIntegrationTest extends Specification {

@LocalServerPort
protected int port

@Shared
protected String addressToUseForTests

@Autowired
protected TestRestTemplate restTemplate

@Container
PostgreSQLContainer postgreSQLContainer = new PostgreSQLContainer("postgres:15.3")
}

测试环境Liquibase配置

databaseChangeLog:
- includeAll:
  path: db/changelog/changeset/
- includeAll:
  path: db/changelog/inserts/

注:第一个路径指向建表变更集,第二个路径指向测试数据插入脚本。

完整报错栈

Failed to load ApplicationContext for [WebMergedContextConfiguration@73852720 testClass = 
com.honeybadgersoftware.cheappy.controller.UserControllerITest, locations = [], classes = 
[com.honeybadgersoftware.cheappy.CheappyApplication], contextInitializerClasses = [], 
activeProfiles = [], propertySourceLocations = ["classpath:application-test.properties"], 
propertySourceProperties = 
["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true", 
"server.port=0"], contextCustomizers = 
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with 
name 'liquibase' defined in class path resource 
 [org.springframework.boot.autoconfigure.liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: liquibase.exception.MigrationFailedException: Migration failed for changeset db/changelog/inserts/insert_test_user.yaml::2::Jakub.Kolacz:
 Reason: liquibase.exception.DatabaseException: ERROR: duplicate key value violates unique constraint "user_email_key"
 Details: Key (email)=(john.doe@example.com) already exists. [Failed SQL: (0) INSERT INTO public.users
...
Caused by: liquibase.exception.LiquibaseException: 
liquibase.exception.MigrationFailedException: Migration failed for changeset 
db/changelog/inserts/insert_test_user.yaml::2::Jakub.Kolacz:
 Reason: liquibase.exception.DatabaseException: ERROR: duplicate key value violates unique 
constraint "user_email_key"
Details: Key (email)=(john.doe@example.com) already exists. [Failed SQL: (0) INSERT INTO 
public.users 
...
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique 
constraint "user_email_key"
Szczegóły: Key (email)=(john.doe@example.com) already exists.

调试情况

移除Liquibase插入脚本,改为在测试中通过userRepository.save()手动插入数据时,能正常触发数据库层唯一键异常,测试可以正常执行:

2023-08-11T00:52:59.968+02:00 ERROR 9180 --- [    Test worker] o.h.engine.jdbc.spi.SqlExceptionHelper   : ERROR: duplicate key value violates unique constraint "user_email_key"
 Szczegóły: Key (email)=(john.doe@example.com) already exists.

 could not execute statement [ERROR: duplicate key value violates unique constraint 
"user_email_key"
  Szczegóły: Key (email)=(john.doe@example.com) already exists.] [update users setbuilding_number=?,city=?,flat_number=?,street=?,zip_code=?,email=?,first_name=?,last_name=?,passwo 
 rd=? where id=?]; SQL [update users setbuilding_number=?,city=?,flat_number=?,street=?,zip_code=?,email=?,first_name=?,last_name=?,passwo 
 rd=? where id=?]; constraint [user_email_key]
 org.springframework.dao.DataIntegrityViolationException: could not execute statement [ERROR: 
 duplicate key value violates unique constraint "user_email_key"

手动在本地环境测试接口也能得到正常结果,但使用Liquibase预加载测试数据时,测试启动就失败,未找到解决方案,寻求帮助。

内容的提问来源于stack exchange,提问作者Jakub Kołacz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:10:52