Liquibase 在测试执行后执行迁移

问题描述 投票:0回答:1

我在测试我的应用程序时遇到了非常奇怪的(对我来说)问题,收到此异常:

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)=([email protected]) 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', '[email protected]', '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 作为测试框架
  • 测试容器(Postgresql)来模拟数据库进行测试
  • Liquibase 作为 fms

当我运行测试方法时,我收到“无法加载 ApplicationContext...blablabla”,然后是我在上面写下的异常。 我认为这是 liquibase/testcontainers 配置的问题。让我向您展示测试代码:

    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: "[email protected]",
            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: "[email protected]",
            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)=([email protected]) 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)=([email protected]) 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)=([email protected]) already exists.

为什么测试很乱? 在调试此测试期间,我想看看当我从变更日志中删除插入迁移并在测试中手动插入数据(在执行发布请求之前通过 userRepository.save() )时会发生什么。

意外(?)返回了预期的异常(准确的说是没有到达http层异常,而是返回了db层异常:

 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)=([email protected]) already exists.

 could not execute statement [ERROR: duplicate key value violates unique constraint 
 "user_email_key"
  Szczegóły: Key (email)=([email protected]) 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"

这是预期的例外。 我还尝试手动测试它(通过向本地环境发送请求),结果很好,所以我知道整个控制器代码工作正常。

我试图找到一些有关它的东西,但我无法在任何地方找到解决方案。我尝试了 testContainer 的不同配置,达到了 liquibase 配置,不幸的是我没有找到解决方案,甚至没有关于类似问题的单个帖子/文章。

你们中的一些人可能也遇到过像我这样的问题吗?

感谢您的任何帮助/提示。

java spring-boot liquibase spock testcontainers
1个回答
0
投票

根据 @Leonard Brunings 在评论中发给我的文章,此问题的解决方案是将这两行插入 application-test.properties 中:

spring.datasource.driver-class-name=org.testcontainers.jdbc.ContainerDatabaseDriver
spring.datasource.url=jdbc:tc:postgresql://localhost:5432/test

而不是对我拥有的 Postgresql 驱动程序和数据源 url 进行分类:

spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.driver-class-name=org.postgresql.Driver

再次非常感谢@Leonardo

© www.soinside.com 2019 - 2024. All rights reserved.