테스트 실행 시간 줄이기
- 우아한테크코스
- 2021. 9. 29. 15:12
- 인수테스트시 DirtiesContext로 테스트 격리를 해주고 있다.
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
- 273테스트 1min 1sec
오래 걸리는 테스트시간을 줄일 수 있는 방법이 없을 까 고민하던 중 좋은 블로그글을 발견했다..! DirtiesContext를 사용하지 않고 테스트 격리를 해서 매번 모든 Context가 새로 생성되는 비효율성을 줄일 수 있다. 테스트에서는 공유자원으로 사용되는 데이터베이스에 대한 격리가 이루어져야 하므로, TRUNCATE를 통해 데이터베이스 초기화를 시켜주는 방법으로 테스트 격리를 하는 것이다.
https://newwisdom.tistory.com/95
- @DirtiesContext제거 하고, 인수테스트 수행 하기 전 DB를 초기화 하도록 변경하니 11sec 387ms로 테스트 수행시간이 현저히 감소했다!
DirtiesContext를 제거하면서 공부했던 내용을 적어본다.
DirtiesContext
- 테스트 수행 전, 수행 후, 각 테스트 케이스를 수행하기 전, 수행한 후에 Context를 재생성하는 역할을 해준다.
- 애플리케이션 컨텍스트가 변경되었을 때 기존 애플리케이션 컨텍스트를 폐기하고, 새로운 애플리케이션 컨텍스르를 생성해서 사용할 수 있도록 한다.
ApplicationContext
- Spring에서 관리하는 빈들이 담겨있는 컨테이너
- Spring에서는 빈의 생성과 관계설정 같은 제어를 담당하는 IoC컨테이너인 빈 팩토리가 존재한다.
- 애플리케이션 컨텍스트는 별도의 정보를 참고해서 빈의 생성, 관계설정 등의 제어 작업을 총괄한다.
테스트 격리
- 테스트들은 서로 순서에 상관없이 독립적으로 수행되어야 한다.
- 테스트 격리가 안 되는 근본적인 원인은 각각의 테스트가 하나의 자원을 공유하기 때문이다.
- 공유자원의 대표주자 '데이터베이스'
- 인수테스트는 실제 운영 환경과 같은 조건에서 테스트 되어야 하므로 '데이터베이스'를 사용해야한다.
- 테스트가 진행됨에 따라 데이터베이스를 건드리게 된다.
@Transactional
- 테스트에서 @Transactional을 통해 롤백하는 전략은 인수테스트에서 사용 불가능하다.
- 인수테스트로 HTTP 요청을 보내는 부분(Client)과, 인수테스트를 위해 서버를 띄운 부분(Server)이 다른 쓰레드이기 때문이다.
EntityManager로 직접 TRUNCATE 쿼리 실행
- 테스트 환경에서만 빈이 등록되도록 설정해주었다.
- 빈등록 시 테이블 이름을 뽑아내고, cleanUp 호출 시 해당 테이블을 TRUNCATE하는 작업을 수행한다.
@Component
@Profile("test")
public class DatabaseCleanup implements InitializingBean {
private final EntityManager entityManager;
private List<String> tableNames;
public DatabaseCleanup(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public void afterPropertiesSet() throws Exception {
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 cleanUp() {
entityManager.flush();
entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate();
for (String tableName: tableNames) {
entityManager.createNativeQuery("TRUNCATE TABLE " + tableName).executeUpdate();
entityManager.createNativeQuery("ALTER TABLE " + tableName +
" ALTER COLUMN ID RESTART WITH 1").executeUpdate();
}
entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate();
}
}
- 인수테스트의 setUp에서 데이터 cleanUp을 수행해준다.
@BeforeEach
protected void setUp() {
RestAssured.port = port;
databaseCleanup.cleanUp();
}
https://tecoble.techcourse.co.kr/post/2020-09-15-test-isolation/
InitialzingBean
- 스프링 빈이 생성될 때 호출된다.
- afterPropertiesSet 메서드
'우아한테크코스' 카테고리의 다른 글
우아한테크코스 글쓰기 아카이브 (0) | 2021.11.20 |
---|---|
[테코톡]TCP/IP (6) | 2021.11.09 |
[팀프로젝트] 5,6주차 (0) | 2021.08.12 |
배포인프라 수업 다시보기 (0) | 2021.08.04 |
[팀프로젝트]4주차 (0) | 2021.07.27 |