TDD, BDD 등 다양한 개발 방법이 있지만 아직까지의 나는 프로젝트 할 때 이러한 개발 방법을 도입해보지 못하고 있다. 나중에 해봐야지.. 이러면서 미뤘놓았다.
그러나 이번에 프로젝트 하면서 TDD는 하지 못했지만 테스트 코드라도 한번 작성하고 커버리지까지 측정해보자는 생각으로 테스트 코드를 짜기 시작했다.
테스트 커버리지를 측정하기 위해서 테스트 커버리지를 측정해주는 라이브러리를 찾아보다 많은 블로그에서 Jacoco를 많이 사용했다. 그래서 많이 사용하는데는 이유가 있겠지하고 Jacoco를 사용하기로 마음 먹었다.
Jacoco는 프로젝트의 코드 커버리지를 분석하고 이를 html로 보고서를 만들어주는 코드 커버리지 프레임워크이다. Jacoco를 이용하면 커버리지가 일정 수준에 도달하지 못하면 빌드를 실패하게 하게 만들수도 있고 다양한 보고서 유형도 제공한다.
처음 테스트 코드를 짤 때는 막막 그 자체였다. 어떻게 어떤걸 테스트 코드를 작성해야 하지?? 이런 생각으로 테스트 클래스를 하나 만들고 검정 Intellij 화면만 바라보고 있었다. 그러다 같이 동아리하는 친구가 Junit 5와 Mockito에 대해 알려주어 이에 대해 알아보기 시작했다.
Junit 5은 많은 개발자들이 사용하고 있는 테스팅 프레임워크로 굉장히 중요한 프레임워크이다. 스프링 2.? 버전부터는 Junit 5가 자동으로 포함되어 있기 때문에 따로 설정해줄 필요가 없다. Junit도 나중에 시간이 되면 더 알아보고 포스트로 다루고 싶다.
Mockito에 대해 검색해보면 Mock이란 단어가 굉장히 많이 나온다. 내가 이제까지 들어본 Mock이란 미리 정의된 데이터를 의미하는 줄 알았다. 그러나 Mock이란 모의, 가짜라는 뜻으로 테스트시 실제 데이터가 아닌 가짜 데이터를 이용하여 테스트의 효율성을 높이는데 사용된다.
그렇다면 Mockito란 Mock 쉽게 만들고 Mock의 행동을 정하는 stubbing, 정상적으로 작동하는지에 대한 Verift 등 다양한 기능을 제공해 주는 프레임 워크이다.
이제 Junit, Mockito, Jacoco 이렇게 대충 알아보았다. 그러면 이제 코드를 짜볼까? 하고 여러 깃허브와 블로그에 올라왔있는 코드를 분석하기 시작했다. 사람들이 주는 given-when-then 방식으로 코드를 짰고, Mockito는 비즈니스 로직과 Repository에 주로 사용하였다.
Given-When-Then 패턴이란 테스트 코드 작성시 주로 사용하는 패턴이다. 준비/실행/검증 세 부분으로 나누어 테스트를 실행하는 방법이다. 아래는 나의 테스트 코드 중 일부를 예시로 설명해보겠다.
@Test
void ID로_수업을_조회한다() {
//given
given(courseRepository.findById(anyLong())).willReturn(Optional.of(Course.builder()
.name("과목1")
.build()));
//when
Course course = courseService.findById(1L);
//then
assertThat(course.getName()).isEqualTo("과목1");
}
given 부분에는 준비과정의 코드를 작성한다. id로 Course를 조회할때 어떤 id를 넣어도 과목1이라는 Course를 리턴하게 만들었다. when은 실행 코드로 실제 CourseService의 findById를 실행한다. then은 when 부분에서 findById를 통해 리턴된 Course와 given 부분에서 반환하게한 Course가 같은지 검증한다.
내가 작성한 테스트 코드가 잘 작성한 테스트 코드인지는 몰라도 나는 이러한 방식으로 Service 계층과 Repository에 대한 코드를 작성하였다.
여기서 given()이라는 메소드는 BDDMockito라는 클래스를 사용한 것이다. BDD는 나중에 TDD에 대해 포스트를 작성할 때 보충 설명해보겠다!
서비스 계층에 대한 테스트 코드는 이제 공부해본 대로 나름 짜기 시작했는데 컨트롤러에 대한 테스트 코드는 어떻게 짜야하는지 또 알아보기 시작했다. 많은 블로그와 깃헙을 보면서 MockMvc라는 Mockito가 제공하는 객체를 사용해서 테스트 코드를 작성했다. 그래서 나도 MockMvc를 이용하려 했지만 우연히 어떤 블로그에서 REST Assured라는 것에 대해 알게되어 이를 사용하기로 했다.
MockMvc는 Mockito에서 제공하는 라이브러리로 간단한 API 테스트를 하고 따로 설정할 필요없이 사용하면된다. 그러나 이는 내부 개발자의 관점에서 사용하는 테스트용 라이브러리이다. REST Assured는 마치 외부에서 요청하고 응답을 수신하는 듯한 느낌을 준다. REST Assured는 요청과 응답 뿐만아니라 검증까지 가능하다. 내가 생각하기에는 나는 MockMvc만으로도 충분히 테스트 코드 작성이 가능하지만 오버엔지니어링일지 몰라도 한번 REST Assured를 사용해보고 싶었다.
다음은 REST Assured를 이용한 코드이다.
@Test
void ID에_맞는_수업이_없으면_404를_반환한다(){
//given
final String accessToken = getAccessToken();
//when
ExtractableResponse<Response> 수업_조회 = 수업_조회(accessToken, 1L);
//then
assertThat(수업_조회.statusCode()).isEqualTo(404);
}
REST Assured 적용기는 꼭 포스트로 다룰 것이다. 왜냐하면 나의 나름대로 복잡하게 구현했다.. 물론 다른 블로그와 깃헙을 보면서 많은 개발자분들의 코드를 짜집기 한 거지만 내 나름대로 내 프로젝트에 녹여냈다.
테스트 코드를 현재에도 작성하고 있지만 작성하면서 이 테스트 코드가 맞는 것인가에 대한 의문점이 계속 든다. 간단한 테스트여도 이렇게 하는게 맞는지 피드백이 없으니.. 외로운 싸움같다. 곧 학기가 끝나고 방학이 되면 꼭 테스트 코드에 대해 많이 공부해 봐야겠다.
그리고 테스트 코드를 작성하면서 기존 코드에 오류도 많고 리펙토링도 자연스럽게 된다!! 이래서 테스트 코드를 작성하나 싶었다. TDD는 엄두가 안났는데 다음에 TDD로 한 번 프로젝트를 하면 좋을 것 같다. 뭔가 전에보다는 할 수 있을 것 같은 느낌이 든다...