
테스트 커버리지 60퍼 이상을 맞추는 과제를 진행하다 오기가 생겨서...
100%에 도전해보기로 했다.
@Generated 사용은 비밀...
주말을 갈아넣어 결국 완성해낸 100%!!
Missed Branches 에서 몇개 빠졌다고는 하는데... 내가 봤을 땐 다 검사가 진행된 부분 같아서 수정하지 못하고 월요일에 질문을 해봐야 할 것 같다.
테스트 코드를 작성하며 어려웠거나 고민됐던 부분들을 정리해보자.
그때그때 정리를 하지 못했어서 기억에 의존해 글만 작성되는 부분이 많을 것 같다.
controller 테스트를 진행하며 로그인, 혹은 인가가 필요한 요청에서 테스트를 진행할 때, 기존에 설정해 둔 interceptor 에 걸려서 테스트가 이루어지지 않았다.
물론 MockHttpSession 을 만들어서 로그인처리, 인가처리를 한 후 작성을 할 수 있지만 매번 그런식으로 진행하는게 이상해서 방법을 찾아보기로 했다.
처음에는 interceptor 자체를 MockitoBean 으로 등록해 기능을 없애버리고 실행하니 테스트가 잘 되었다. 그러나 인터셉터가 많아지는 경우 라던지 좀 짜치는 방법이라는 피드백을 받고 다른 방법을 찾기로 했다.
fakeInterceptor 를 생성해 테스트 클래스에서 @Import 해주어 모든 요청을 통과시키려고 했지만, TestWebConfig 를 만들어 fakeInterceptor 를 등록하고 Import 해주어도 기존 인터셉터를 패스하지 못했다. 실패한 이유는 모르겠지만 다른 방법으로 시도해보았다.
자료를 찾아보다 WebMvcTest 에서 excludeFilter 를 지정할 수 있다는 사실을 알게되었고, 다음과 같이 설정해서 문제를 해결했다.
@WebMvcTest(value = ReservationController.class,
excludeFilters = @ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = {
WebConfig.class
}
))
class ReservationControllerTest {
// test code
}
이런식으로 처리하니 요청이 인터셉터에 걸리지 않고 넘어왔다.
모든 컨트롤러 테스트에 저 코드를 추가해주는 것이 불편해서 다음 프로젝트에서는 supportTestClass 를 abstract 로 만들어 사용해보려고 한다.
레포지토리 테스트를 작성하는 과정에서 각 테스트 메서드에 데이터를 저장하고, 해당 데이터를 이용해 메서드를 사용하는 로직을 작성했다.
ex) findUserById
userRepository.save(new User("name")); User findUser = userRepository.findUserById(1L); assertEquals(1L, findUser.getId());
이런식으로 로직을 작성하니, 메서드 하나씩 테스트를 진행할 때 문제가 없었지만 테스트 클래스 전체를 돌려보면 에러가 발생했다.
이유는 다음과 같다.
테스트 환경에서 @Transactional 혹은 @DataJpaTest 등이 적용된 상태에서 엔티티를 저장하면, DB의 AUTO_INCREMENT 시퀀스가 증가한 뒤, 트랜잭션 롤백으로 인해 데이터는 사라지지만 시퀀스 값은 복원되지 않는다.
그래서 다음 테스트나 실제 코드에서 새로 INSERT할 때 아이디가 ‘중간에 비는 현상’(밀리는 현상)이 발생한다.
예시
테스트 코드에서 id = 1로 사용자 저장
트랜잭션 롤백 (데이터 삭제)
다음 테스트 또는 실제 코드에서 새 데이터 저장 시 DB 아이디가 2부터 시작
이를 해결할 수 있는 방법은 다음과 같다.
1. H2 인메모리 DB를 사용 시
나는 3번 방법을 사용해 해결했다.
문제가 더 있던거 같은데 일단 정리가 되는 부분만 적어봤다. 문제들을 근본적으로 해결한 부분도 있고 발등의 불만 끈 부분도 있는거 같은데 앞으로 이러한 점들을 고려하며 테스트를 작성하면 더 좋은 코드가 나올거라고 생각한다.