본문 바로가기

Development/Spring Framework

스프링 부트에서 테스트 코드 작성

 

견고한 서비스를 위해 개발자나 팀에서 TDD 혹은 최소한 테스트 코드를 작성합니다. 즉, 대부분의 서비스 회사는 테그트 코드에 관해 요구하고 있습니다.

 

테스트 코드 소개

중요하게 집고 가야 할 것은 TDD와 단위 테스트는 다른 이야기 입니다.

  • TDD

    테스트 주도 개발로 테스트 코드를 먼저 작성하는 것부터 시작합니다. 실패하는 테스트를 먼저 작성하며(RED), 테스트가 통과하는 프로덕션 코드를 작성하고(Green), 테스트가 통과하면 프로덕션 코드를 리팩토링합니다.(Refactor)

  • 단위 테스트

    이는 TDD의 첫 번째 단계인 기능 단위 테스트 코드를 작성하는 것을 이야기합니다. TDD와 달리 테스트 코드를 꼭 먼저 작성해야 하는 것이 아니며, 리팩토링도 포함라지 않습니다. 순수하게 테스트 코드만 작성하는 것을 이야기합니다.

repo.yona.io/doortts/blog/issue/1

 

"TDD 실천법과 도구" 책 전체를 PDF 공개합니다.

2010년 6월에 출간되었던 "TDD 실천법과 도구" 책 전체를 PDF로 공개합니다. 책소개: http://naver.me/GaYZCDjD Updated --- - [1장 - 테스트주도개발 Test Driven Development](https://repo.yona.io/doortts/blog/issue/2) - 18.07.18 -

repo.yona.io

 

단위 테스트 코드 작성의 이점은 아래와 같습니다.

 

  • 개발단계 초기에 문제를 발견할 수 있습니다.

  • 개발자가 후에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인할 수 있습니다.

  • 기능에 대한 불확실성을 감소시킬 수 있습니다.

  • 시스템에 대한 실제 문서를 제공합니다. 즉, 단위 테스트 자체가 문서로 사용할 수 있습니다.

단위 테스트를 배우기 전, 코드를 수정한다면 톰캣(WAS)을 멈췄다가 다시 실행하는 일을 반복합니다. 왜냐하면 직접 수정된 기능을 확인하기 위해서 재실행이 필요하기 때문입니다.

 

하지만 테스트 코드를 작성하면 이와 같은 문제가 해결됩니다. 사람이 눈으로 검증할 필요 없이 자동 검증이 가능해지기 때문입니다.

 

또한 개발자가 만든 기능을 안전하게 보호할 수 있습니다. 예시로 기능이 추가되어 테스트합니다. 기능이 잘 작동되어 오픈하였더니, 기존에 잘 작동되던 다른 기능에 문제가 발생합니다. 이는 서비스를 통합하는 과정에서 빈번하게 발생하는 일인데. 이때 모든 기능을 확인하는 것에 많은 자원이 발생합니다. 이처럼 새로운 기능이 추가될 때, 기존 기능이 잘 작도오디는 것을 보장하는 것이 테스트 코드입니다. 미리 테스트 코드를 구현해두었다면, 테스트 코드를 수생하기만 하면 문제를 찾을 수 있기 때문입니다.

 

xUnit

 

대표적인 테스트 프레임워크로 xUnit이 존재합니다. 개발환경(x)에 따라 Unit 테스트를 도와주는 도구입니다.

 

  • Java - JUnit
  • DB - DBUnit
  • C++ - CppUnit
  • .net - NUnit

 

Hello Controller 테스트 코드 작성하기

 

 

패키지명은 도메인의 거꾸로 갑니다. ex) naver.com -> com.naver

패키지를 추가한 뒤 java class를 생성합니다.

 

위 코드를 설명하겠습니다.

 

  • Application 클래스는 앞으로 만들 프로젝트의 메인 클래스입니다.

  • @SpringBootApplication은 스프링 부트의 자동 설정, Bean 읽기와 생성을 모두 자동으로 설정합니다. 특히 @SpringBootApplication이 있는 위치부터 설정을 읽어가기에 항상 프로젝트 최상단에 위치해야만 합니다.

  • main 메서드에서 실행하는 SpringApplication.run으로 내장 WAS를 실행합니다.

    내장 WAS(Web Application Server)는 별도로 외부에 WAS를 두지 않고 실행하는 것을 이야기합니다. 그러면 항상 서버에 톰캣을 설치할 필요 없이 스프링 부트로 만들어진 JAR 파일로 실행합니다.

    스프링 부트에서는 내장 WAS를 사용하는 것을 권장합니다. 이는 어느 개발환경에서든 같은 환경에스 스프링 부트를 배포할 수 있기 떄문입니다.

 

 

생성한 web package는 컨트롤러와 관련된 클래스를 담기위한 것입니다. 위 코드의 설명을 해보도록 하겠습니다.

 

  • @RestController

    컨트롤러를 JSON을 반환하는 컨트롤러로 만들어줍니다. @ResponseBody를 각 메서드마다 선언했던 것을 한 번에 사용할 수 있게 해준다고 생각하면 됩니다.

  • @GetMapping

    HTTP Method인 Get의 요청을 받을 수 있는 API를 만들어주는 것입니다.

 

위에 작성된 간단한 API를 WAS를 실행하지 않고, 테스트 코드로 검증해보겠습니다.

 

 

  • @RunWith(SpringRunner.class)

    테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킵니다. 여기서는 SpringRunner라는 스프링 실행자를 사용함으로, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 합니다.

  • @WebMvcTest

    Web(Spring MVC)에 집중할 수 있는 어노테이션으로 선언할 경우 @Controller, @ControllerAdvice 등을 사용할 수 있습니다.

  • @Autowired

    스프링이 관리하는 빈(Bean)을 주입 받습니다.

  • private MockMvc mvc;

    웹 API 테스트를 할 때 사용합니다. 스프링 MVC 테스트의 시작점입니다. 이로 HTTP Method API 테스트를 할 수 있습니다.

  • mvc.perform(get("/hello"))

    MockMvc를 통해 /hello 주소로 HTTP Get 요청을 합니다. 체이닝이 지원돼 여러 검증을 이어서 할 수 있습니다.

  • .andExpect(status().isOk())

    mvc.perform의 결과를 검증합니다. HTTP Header의 status를 검증합니다. 우리가 알고 있는 200, 404, 500 등의 상태를 검증합니다.

    OK는 200인지 아닌지를 검증하는 것입니다.

  • .andExpect(content().string(hello))

    mvc.perform의 결과를 검증합니다. 응답 본문의 내용을 검증합니다. Controller에서 "hello"를 리턴하기에 값이 맞는지 검증합니다.

 

발생한 에러

Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test

이는 @SpringBootApplication이 선언된 클래스가 존재하는 패키지의 하위 패키지에 존재하지 않아 발생하는 에러입니다. 패키지의 경로를 확인해주세요.

 

테스트가 통과될 경우 위와 같이 나타나는 것을 확인할 수 있습니다. 이는 .andExpect(status().isOk()).andExpect(content().string(hello))가 테스트를 통과했음을 의미합니다. 

 

정상 값이 출력되는지 확인해보도록 하겠습니다. main method를 실행합니다. 이때 로그에서 톰캣 실행 포트를 볼 수 있습니다.

 

 

localhost와 포트번호를 입력하여 정상 출려됨을 확인할 수 있습니다.

 

테스트 코드는 반드시 작성해 확인해야하며, 통과하여도 브라우저로 반드시 한 번씩 검증을 해야합니다. 그래야만 견고한 소프트웨어를 만드는 역량을 성장시킬 수 있습니다.