[우아한테크코스 4기] 220721 F12 개발일지

Jihoon Oh·2022년 7월 22일
1

우아한테크코스 4기

목록 보기
27/43
post-thumbnail

오늘 진행한 일

스프린트 2 배포버전에 반영하지 못한 수정사항 수정

스프린트 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 메서드는 스프링부트가 프로퍼티를 다 읽어오면 실행이 되고, executeAcceptanceTest 클래스의 @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();
    }
}

이렇게 하니 심지어 각각 다른 도메인에 대한 테스트더라도 인수 테스트 끼리는 빈을 교체하거나 할 일이 없어서 컨텍스트를 다시 불러오지 않게 되었고, 인수 테스트가 오히려 가장 빠른 속도를 보일 정도로 속도가 개선되었다.

인수 테스트 격리에 대한 보다 자세한 설명을 원한다면 인수테스트에서 테스트 격리하기를 참고하자.

profile
Backend Developeer

0개의 댓글