我在测试我的应用程序时遇到了非常奇怪的(对我来说)问题,收到此异常:
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);
}
}
我正在使用:
当我运行测试方法时,我收到“无法加载 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 配置,不幸的是我没有找到解决方案,甚至没有关于类似问题的单个帖子/文章。
你们中的一些人可能也遇到过像我这样的问题吗?
感谢您的任何帮助/提示。
根据 @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