[혼자 구현하는 웹 서비스] 2장 스프링 부트에서 테스트 코드를 작성하자

2020. 7. 1. 21:38책/스프링 부트와 AWS로 혼자 구현하는 웹 서비스

2장 스프링 부트에서 테스트 코드

테스트 코드는 내가 관심있게 공부한 분야이기도 하다.

어떠한 책이나 플랫폼을 통해 공부해도 테스트 코드의 중요성은 항상 강조하는 것 같다.

이 책에서 또한 스프링 부트에서의 테스트 코드 작성법에 대해 기본적인 내용을 배울 수 있었다.

1. 테스트 코드

개발자로 취업하기 위해 공부중인 사람이라면 누구나 한번쯤 우대사항에 적혀있는 테스트 코드 작성경험을 본 적이 있을 것이다. 그만큼 대부분의 IT 서비스 회사가 테스트 코드를 중요시 하고 있다. 견고한 서비스를 만들기 위해서는 TDD를 하거나 최소한 단위 테스트 코드를 꼭 작성해야 한다는 이유이다. TDD와 단위 테스트 코드에는 차이점이 있다. TDD는 테스트가 주도하는 개발을 뜻한다. 즉, 테스트 코드를 먼저 작성하는 개발 방식이다. 흔히 RED-GREEN-REFACTOR순으로 이루어지는데, 이와 같은 과정을 배우기 위해 많은 검색을 해보았지만 쉽게 익혀지지 않는 고급 기술이라는 생각이 들었다. 반면 단위 테스트는 TDD의 첫 번째 단계인 기능 단위의 테스트코드를 작성하는 것을 이야기 한다. TDD와 달리 테스트 코드를 꼭 먼저 작성해야 하는 것도 아니고, 리팩토링을 포함하는 것도 아니기 때문에 비교적 테스트 코드 작성에 대한 감을 살리기에 적합하다. 이 책에서 또한 단위 테스트 코드를 작성하는 방법에 대해 알려주고 있다.

2. 테스트 코드 작성의 중요성

테스트 코드의 중요성에 대해서는 따로 글을 작성한 적이 있다. 이 책에서는 위키피디아에서 검색한 '테스트 코드의 중요성'과 필자의 경험에서 우러난 이유를 설명하고 있다.

  • 단위 테스트는 개발 단계 초기에 문제를 발견하게 도와준다.
  • 단위 테스트는 개발자가 나중에 코드를 리팩토링 하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인할 수 있다.
  • 단위 테스트는 기능에 대한 불확실성을 감소 시킨다.
  • 단위 테스트는 시스템에 대한 실제 문서를 제공한다. 즉, 단위 테스트 자체가 문서로 사용될 수 있다.

이 밖의 이유들에 대해서는 따로 정리한 글을 참고하면 되겠다.(Junit)

 

3. Hello Controller 테스트 코드 작성하기

테스트 코드 작성에 앞서 프로젝트의 메인 클래스를 먼저 살펴 보자.

@SpringBootApplication 어노테이션으로 인해 스프링 부트의 자동 설정, 빈 읽기와 생성을 모두 자동으로 설정하게 된다. 

이 어노테이션이 있는 위치부터 설정들을 읽어나가기 때문에 이 클래스는 항상 프로젝트의 최상단에 위치하는 것이 좋다. 

(이와 관련된 내용도 스프링 부트 개념과 활용이라는 강의를 듣고 정리한 적이 있다. src/main/java에 바로 위치시키는 것이 아니라 최 상단 패키지를 만들고 그곳에 위치시키는 이유에 대해!)

 

SpringApplication.run메소드는 내장 WAS를 실행시키는 것이다. 이렇게 함으로써 외부의 WAS없이 스프링 부트로 만들어진 JAR파일 만으로도 프로젝트를 실행할 수 있게 된다. 이렇게 하면 언제 어디서나 같은 환경에서 스프링 부트 프로젝트를 배포할 수 있게 된다는 장점이 있다. 

 

메인 클래스는 이정도로 정리하고 테스트 코드를 실습할 controller를 만든다.

 

@RestController : 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 준다.

예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한번에 사용할 수 있게 해준다고 생각하면 된다.

 

@GetMapping : HTTP 메소드인 Get요청을 받을 수 있는 API로 만들어 준다. 

 

위의 컨트롤러는 /hello라는 요청을 받았을때 hello라는 문자열을 반환해준다. 이것을 확인하기 위해 WAS를 실행해 볼 수 있지만, 테스트 코드로 검증하는 방법에 대해 정리해 보겠다. (매우 간단하기 때문에 WAS로 보는 것이 낫긴하지만...)

 

3. 테스트 클래스

 

이 짧은 코드에 정리해야 할 내용이 아주 많다...

 

@RunWith(SpringRunner.class) : 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시키게 해준다. 여기서는 SpringRunner라는 스프링 실행자를 사용하는데, 스프링 부트 테스트와 JUnit  사이에 연결자 역할을 하게 되는 것이다. 

 

@WebMvcTest : 스프링 테스트의 여러 어노테이션중 WebMvcTest는 좀 더 웹 테스트에 집중할 수 있도록 해준다. 

@Controller, @ControllerAdvice등을 사용할 수 있으며, @Service, @Component, @Repository는 사용할 수 없다.

 

@Autowired : 스프링이 관리하는 Bean을 주입받는다.

 

MockMvc : 웹 API를 테스트할 때 사용하는 객체이다. 스프링 MVC테스트의 시작점이며, 이 클래스를 통해 HTTP GET, POST등에 대한 API테스트를 할 수 있다.

 

mvc.perform(get("/hello")) : MockMvc를 통해 /hello 주소로 HTTP GET 요청을 한다. 체이닝이 지원되기 때문에 이 요청에 대해 기대되는 응답들을 아래에 이어서 검증할 수 있다.

 

andExpect(status().isOk()) : mvc.perform의 결과를 검증한다. HTTP Header의 status 가 Ok인지 검증한다. status 200

 

andExpect(content().string(hello)) : mvc.perform의 결과를 검증한다. 응답 본문의 내용이 hello인지 검증한다. 

 

위와 같이 테스트 코드가 통과하는지 확인한다. 이때 의심쩍다면 WAS를 실행시켜 localhost:8080/hello를 통해 검증할 수 있지만, 꼭 테스트 코드를 작성하고 통과하는것을 확인하는 습관을 들이는 것이 좋겠다.

 

4. 롬복

롬복은 '스프링부트 시작하기'라는 책에서 실습을 진행할때도 사용했던 라이브러리 이다. 이제는 자바 개발자들의 필수 라이브러리가 되기도 한 롬복은 Getter, Setter, 기본 생성자, toString등을 어노테이션으로 자동 생성해 준다. 이클립스로 실습을 진행할 때는 상당히 복잡했지만, 인텔리제이에선 플러그인 덕분에 쉽게 설정이 가능했다. 

먼저, build.gradle에 의존성을 추가해 준다.

 

 

이후 lombok플러그인을 설치하고,

settings> build > compile > annotation processor에서 enable annotaion processing을 체크해주어야 한다.

 

5. 롬복 사용

 

롬복을 사용하면 위와같이 @Getter어노테이션을 통해 선언된 모든 필드의 get메소드를 자동으로 생성할 수 있다.

@RequiredArgsConstructor는 선언된 모든 final 필드가 포함된 생성자를 생성해 주고, final이 없는 필드는 생성자에 포함되지 않게 된다.

 

Dto를 구성하고 테스트 코드까지 확인해 보면 lombok이 잘 작동했다는 것을 확인할 수 있다.