Dirties Context를 사용하지 않습니다.클래스 모드AFTER_EACH_TEST_METHOD with Test Containers
와의 통합 테스트를 실시하고 있습니다.testcontainers
그리고.spring-boot
스크립트 초기화 중 문제가 발생하였습니다.2개의 스크립트가 있습니다.schema.sql
그리고.data.sql
.
사용할 때DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD
정상적으로 동작하지만, 각 테스트 후에 새로운 용기를 재실행하는 것은 좋은 생각이 아닙니다.물론 그것은 시험을 매우 느리게 만든다.
한편으로 사용할 때는DirtiesContext.ClassMode.AFTER_CLASS
단, 다음과 같은 예외가 있습니다.
org.springframework.jdbc.springsource.init 를 지정합니다.Script Statement Failed Exception:클래스 경로 리소스 [sql/mariadb/schema]의 SQL 스크립트 문 #1을 실행하지 못했습니다.sql]: 테이블이 있는 경우 드롭
client
; nested 예외는 java.sql입니다.SQLIntegrityConstraintViolation(SQLIntegrityConstraint 위반)예외: (variable=4) 부모 행을 삭제하거나 업데이트할 수 없습니다. org.springframework.jdbc.sariplesource.init에서 외부 키 제약 조건이 실패합니다.ScriptUtils.executeSqlScript(ScriptUtils.java:282)~[ spring - jdbc - 5 . 3 . 13 . jar : 5 . 3 . 13 ] 。원인: java.sql.SQLIntegrityConstraintViolation(SQLIntegrityConstraint 위반)예외: (variable=4) 상위 행을 삭제하거나 업데이트할 수 없습니다. 외부 키 제약 조건이 실패합니다...원인: org.mariadb.jdbc.internal.util. 예외.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();
}
}
schema.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;
data.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');
제가 뭘 놓쳤나요?조언은 매우 환영받을 것이다.
그@Sql
디폴트에 따라 실행됩니다.BEFORE_TEST_METHOD
각 테스트 방법 전에 실행됩니다.즉, 테스트를 실행하기 전에 SQL이 실행됩니다.그러나 여러 테스트에 동일한 데이터베이스를 재사용함으로써 SQL 스크립트가 "유휴" 상태가 아닌 경우, 즉 동일한 데이터베이스에 두 번 안전하게 적용할 수 없는 경우 오류가 발생할 수 있습니다.
이 기능을 사용하려면 다음과 같은 여러 가지 방법이 있습니다.
에 1개 추가
AFTER_TEST_METHOD
청소할 수 있습니다.그러면 기본적으로 이 테스트에 의해 추가된 모든 항목(에 의해 추가된 항목 포함)이 제거됩니다.@Sql
를 참조해 주세요.이렇게 하면 각 테스트 실행 후 DB가 "정리"되고 모든 실행이 안전하게 동일한 SQL 스크립트를 다시 적용할 수 있습니다.또는 여러 번 실행해도 안전합니다.이는 스크립트에 따라 다르지만 오류 없이 두 번 실행할 수 있도록 SQL을 작성할 수 있다면 이 작업도 가능합니다.
「 」를 사용하지
@Sql
를도 있습니다.DatabasePopulator
콩알이렇게 하면 전체 응용 프로그램 컨텍스트가 생성될 때 SQL 코드가 한 번만 실행됩니다.ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ, ㄴ,
@Transactional
스프링 랩을 테스트 실행 주변의 트랜잭션으로 만들고 나중에 롤백합니다.불행히도, 나는 현재 이것이 얼마나 좋은 결과를 가져올지 모르겠다.@Sql
효과가 있을 수도 있고 없을 수도 있지만 75%의 확률로 효과가 있을 수도 있습니다.물론 여기에는 몇 가지 영향이 있습니다(실제로 DB에 기록된 내용은 없으며 코드 내에서 트랜잭션을 사용하는 경우 문제가 발생할 수 있습니다).
아마 이 모든 방법들이 당신의 문제를 해결해 줄 것입니다.
언급URL : https://stackoverflow.com/questions/71625930/dont-want-to-use-dirtiescontext-classmode-after-each-test-method-with-testconta
'programing' 카테고리의 다른 글
vue j를 사용하여 여러 입력 필드 리피터를 작성하는 방법 (0) | 2023.01.03 |
---|---|
데베지움 - 마리아에서 DATE 유형에 관한 문제DB (0) | 2023.01.03 |
반환할 열을 추가할 때 Mysql 쿼리가 느려지는 이유는 무엇입니까? (0) | 2023.01.03 |
템플릿 태그를 사용한 Vue 및 조건부 렌더링 (0) | 2023.01.03 |
PHPExcel 및 텍스트 래핑 (0) | 2023.01.03 |