반응형
각 테스트 케이스를 개별적으로 실행할 경우 잘 통과되는데, 클래스로 전체를 한 번에 실행할 경우 실패하는 경우가 있다.
나의 경우 엔티티의 id값이 테스트를 진행하면서 증가되는 문제점이 있었다. (물론 개별적으로 진행하면 성공함)
이러한 문제점을 해결하기 위해 매 테스트마다 테이블 데이터를 초기화시켜 주는 작업을 추가시켜 주었다.
// 원하는 결과물
@BeforeEach
void beforeEach() {
databaseCleaner.execute();
}
DatabaseCleaner 클래스 생성
전체적인 흐름
- 최초로 한 번 db에 들어있는 table 이름을 받아서 list에 담아줍니다.
- 매번 테스트가 진행되기 전 table의 데이터를 초기화해줍니다.
전체 코드
@Component
public class DatabaseCleaner {
@PersistenceContext // entityManager 전용 @Autowired
private EntityManager entityManager;
private List<String> tableNames; // table 이름을 담을 리스트
@PostConstruct // spring 생명주기에서 의존관계 주입까지 마친 상태에서 실행되는 어노테이션
public void init() { // (1)
tableNames = entityManager.getMetamodel().getEntities().stream()
.filter(e -> e.getJavaType().getAnnotation(Entity.class) != null)
.map(e -> CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, e.getName()))
.collect(Collectors.toList());
}
@Transactional
public void execute() { // (2)
entityManager.flush();
entityManager.createNativeQuery("SET foreign_key_checks = 0").executeUpdate();
for (String tableName : tableNames) {
entityManager.createNativeQuery("TRUNCATE TABLE " + tableName).executeUpdate();
}
entityManager.createNativeQuery("SET foreign_key_checks = 1").executeUpdate();
}
}
(1) init 작업
@Entity 붙은 클래스 이름을 Camel case에서 Snake case로 바꿔준 뒤 리스트에 저장한다.
ex) PostLike -> post_like
작업 수행 후 모든 테이블 명이 list에 담긴다.
db에 들어가는 table명을 알아야지 명령어를 통해 테이블 초기화 작업을 수행할 수 있다.
+ CaseFormat을 쓰기 위해 의존성을 추가해줘야 한다.
// google guava
implementation group: 'com.google.guava', name: 'guava', version: '31.1-jre'
(2) execute 작업
- 외래키 제약 조건을 꺼준다.
- table 데이터를 지워준다.
- 외래키 제약 조건을 켜준다.
데이터베이스 종류마다 명령어가 조금씩 다를 수 있습니다. 위 코드의 개발환경은 mysql입니다.
- TRUNCATE를 쓰는 이유
delete의 경우 row 하나씩 삭제해 주기 때문에 느리지만 truncate는 한 번에 삭제해 줘서 속도가 빠르다.
혹시 이런 에러가 뜬다면
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'databaseCleaner' defined in file End\build\classes\java\test\com\masil\common\DatabaseCleaner.class]: Invocation of init method failed; nested exception is java.lang.NullPointerException
DB의 테이블명이 제대로 tableList에 담겼는지 확인해 보자.
참고자료
- 구현 방법
- https://velog.io/@janeljs/test-database-init
- @PersistenceContext 쓰는 이유
- https://batory.tistory.com/497
- 스프링 생명주기
- https://devlog-wjdrbs96.tistory.com/321
반응형
'spring boot > 테스트' 카테고리의 다른 글
spring boot의 test db환경에 testcontainers 적용 [삽질 후기] (0) | 2023.03.17 |
---|---|
@WebMvcTest 환경에서 Spring Security 403 에러 (0) | 2023.01.28 |
댓글