스프린트 2 데모데이를 위한 배포 버전이 수요일을 끝으로 완료되어서, 수요일까지 미처 마무리하지 못한 자잘한 기능들을 구현은 하되 배포는 데모데이가 끝난 이후 진행하기로 했다.
DirtiesContext
제거인수 테스트는 웹 환경을 생성해서 테스트해야 하는 관계로 @Transactional
어노테이션이 작동하지 않는다. 그래서 여태까지 인수 테스트는 테스트 격리를 위해 @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
를 사용하고 있었다. 하지만 이 방식을 사용하니 테스트 작동 시간이 굉장히 길어진다는 단점이 있었다. 단순히 테스트만 길어지는 것이 아니라, 이로 인해 빌드 시간까지 길어진다. 테스트 시간을 단축하기 위해 @DirtiesContext
를 제거하는 방법을 찾았고, 엔티티 매니저를 사용해서 데이터베이스를 계속 초기화해주는 방법을 사용했다.
@Component
public class DatabaseCleanup implements InitializingBean {
@PersistenceContext
private EntityManager entityManager;
private List<String> tableNames;
@Override
public void afterPropertiesSet() throws Exception {
tableNames = entityManager.getMetamodel().getEntities().stream()
.filter(it ->
it.getJavaType().getDeclaredAnnotation(Table.class) != null)
.map(it -> it.getJavaType().getDeclaredAnnotation(Table.class).name())
.collect(Collectors.toList());
}
@Transactional
public void execute() {
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();
}
}
엔티티 매니저에 등록되어 있는 테이블 이름을 전부 받아오는 afterPropertiesSet
메서드와 해당 테이블들의 데이터를 전부 TRUNCATE
하고 AUTO_INCREMENT
설정이 되어있는 ID 값의 시작을 0으로 초기화하는 execute
메서드가 존재한다. afterPropertiesSet
메서드는 스프링부트가 프로퍼티를 다 읽어오면 실행이 되고, execute
는 AcceptanceTest
클래스의 @BeforeEach
설정으로 들어간다.
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
public class AcceptanceTest {
@LocalServerPort
private int port;
@Autowired
private DatabaseCleanup databaseCleanup;
@BeforeEach
void setUp() throws Exception {
if (RestAssured.port == UNDEFINED_PORT) {
RestAssured.port = port;
databaseCleanup.afterPropertiesSet();
}
databaseCleanup.execute();
}
}
이렇게 하니 심지어 각각 다른 도메인에 대한 테스트더라도 인수 테스트 끼리는 빈을 교체하거나 할 일이 없어서 컨텍스트를 다시 불러오지 않게 되었고, 인수 테스트가 오히려 가장 빠른 속도를 보일 정도로 속도가 개선되었다.
인수 테스트 격리에 대한 보다 자세한 설명을 원한다면 인수테스트에서 테스트 격리하기를 참고하자.