【发布时间】:2022-09-30 11:57:59
【问题描述】:
我正在使用 testcontainers 和 spring-boot 进行集成测试,但在初始化脚本时遇到了问题。我有 2 个脚本:schema.sql 和 data.sql。
当我使用DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD时,它工作得很好,但在每次测试后重新运行一个新容器并不是一个好主意。当然,这会使测试变得非常缓慢。
另一方面,当我使用 DirtiesContext.ClassMode.AFTER_CLASS 时,我有这个例外:
org.springframework.jdbc.datasource.init.ScriptStatementFailedException: 执行类路径资源的 SQL 脚本语句 #1 失败 [sql/mariadb/schema.sql]:删除表如果存在
client;嵌套的 例外是 java.sql.SQLIntegrityConstraintViolationException: (conn=4) 无法删除或更新父行:外键 约束失败 org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:282) ~[spring-jdbc-5.3.13.jar:5.3.13] at ... 原因: java.sql.SQLIntegrityConstraintViolationException: (conn=4) 不能 删除或更新父行:外键约束失败... 造成的: org.mariadb.jdbc.internal.util.exceptions.MariaDbSqlException:不能 删除或更新父行:外键约束失败基类:
@Testcontainers @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles(\"it\") @Sql({\"/sql/mariadb/schema.sql\", \"/sql/mariadb/data.sql\"}) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public abstract class BaseIntegrationTest implements WithAssertions { @Container protected static MariaDBContainer<?> CONTAINER = new MariaDBContainer<>(\"mariadb:10.6.5\"); @Autowired protected ObjectMapper mapper; @Autowired protected WebTestClient webTestClient; }集成测试:
class ClientControllerITest extends BaseIntegrationTest { @Test void integrationTest_For_FindAll() { webTestClient.get() .uri(ApplicationDataFactory.API_V1 + \"/clients\") .exchange() .expectStatus().isOk() .expectBody(Success.class) .consumeWith(result -> { assertThat(Objects.requireNonNull(result.getResponseBody()).getData()).isNotEmpty(); }); } @Test void integrationTest_For_FindById() { webTestClient.get() .uri(ApplicationDataFactory.API_V1 + \"/clients/{ID}\", CLIENT_ID) .exchange() .expectStatus().isOk() .expectBody(Success.class) .consumeWith(result -> { var clients = mapper.convertValue(Objects.requireNonNull(result.getResponseBody()).getData(), new TypeReference<List<ClientDto>>() { }); var foundClient = clients.get(0); assertAll( () -> assertThat(foundClient.getId()).isEqualTo(CLIENT_ID), () -> assertThat(foundClient.getFirstName()).isEqualTo(CLIENT_FIRST_NAME), () -> assertThat(foundClient.getLastName()).isEqualTo(CLIENT_LAST_NAME), () -> assertThat(foundClient.getTelephone()).isEqualTo(CLIENT_TELEPHONE), () -> assertThat(foundClient.getGender()).isEqualTo(CLIENT_GENDER_MALE.name()) ); }); } @Test void integrationTest_For_Create() { var newClient = createNewClientDto(); webTestClient.post() .uri(ApplicationDataFactory.API_V1 + \"/clients\") .accept(MediaType.APPLICATION_JSON) .bodyValue(newClient) .exchange() .expectStatus().isOk() .expectBody(Success.class) .consumeWith(result -> { var clients = mapper.convertValue(Objects.requireNonNull(result.getResponseBody()).getData(), new TypeReference<List<ClientDto>>() { }); var createdClient = clients.get(0); assertAll( () -> assertThat(createdClient.getId()).isEqualTo(newClient.getId()), () -> assertThat(createdClient.getFirstName()).isEqualTo(newClient.getFirstName()), () -> assertThat(createdClient.getLastName()).isEqualTo(newClient.getLastName()), () -> assertThat(createdClient.getTelephone()).isEqualTo(newClient.getTelephone()), () -> assertThat(createdClient.getGender()).isEqualTo(newClient.getGender()) ); }); } @Test void integrationTest_For_Update() { var clientToUpdate = createNewClientDto(); clientToUpdate.setFirstName(CLIENT_EDITED_FIRST_NAME); webTestClient.put() .uri(ApplicationDataFactory.API_V1 + \"/clients\") .accept(MediaType.APPLICATION_JSON) .bodyValue(clientToUpdate) .exchange() .expectStatus().isOk() .expectBody(Success.class) .consumeWith(result -> { var clients = mapper.convertValue(Objects.requireNonNull(result.getResponseBody()).getData(), new TypeReference<List<ClientDto>>() { }); var updatedClient = clients.get(0); assertAll( () -> assertThat(updatedClient.getId()).isEqualTo(clientToUpdate.getId()), () -> assertThat(updatedClient.getFirstName()).isEqualTo(clientToUpdate.getFirstName()), () -> assertThat(updatedClient.getLastName()).isEqualTo(clientToUpdate.getLastName()), () -> assertThat(updatedClient.getTelephone()).isEqualTo(clientToUpdate.getTelephone()), () -> assertThat(updatedClient.getGender()).isEqualTo(clientToUpdate.getGender()) ); }); } @Test void integrationTest_For_Delete() { webTestClient.delete() .uri(ApplicationDataFactory.API_V1 + \"/clients/{ID}\", CLIENT_ID) .exchange() .expectStatus().isOk(); } }架构.sql:
DROP TABLE IF EXISTS `client`; CREATE TABLE `client` ( `id` bigint(20) NOT NULL, `first_name` varchar(255) DEFAULT NULL, `last_name` varchar(255) DEFAULT NULL, `gender` varchar(255) DEFAULT NULL, `telephone` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;数据.sql
INSERT INTO client (id, first_name, last_name, gender, telephone) VALUES(1, \'XXX\', \'XXX\', \'MALE\', \'XXX-XXX-XXXX\'); INSERT INTO client (id, first_name, last_name, gender, telephone) VALUES(2, \'XXX\', \'XXX\', \'MALE\', \'XXX-XXX-XXXX\');我错过了什么?一个建议将非常受欢迎。
-
请注意,这不是特定于 Testcontainers 的问题,而是关于在处理测试污染时使用相同的数据库进行多个测试。
标签: java spring testing mariadb testcontainers