[이동준] 테스트 코드 작성하기
Updated:
🧶테스트 코드 작성하기
Java 디렉토리를 마우스 오른쪽 버튼으로 클릭하여, [New -> Package]를 차례로 선택해서 새로운 패키지를 생성한다.
일반적으로 패키지명은 웹 사이트 주소의 역순으로 한다. 예를 들어 admin.java.com 이라는 사이트라면 패키지명은 com.java.admin으로 하면 된다.
freelec 프로젝트를 생성했을 때 사용한 Group id인 ‘com.webservice.book’를 이용해 패키지명을 ‘com.webservice.book.web’으로 지정하겠다.
이제 새로 생성한 패키지 아래에 Java 클래스를 생성한다. 패키지와 마찬가지로 [New -> Java class]를 차례로 선택한다.
클래스의 이름은 MainApp으로 지정했다.
MainApp 클래스의 코드는 다음과 같이 작성한다.
package com.webservice.book.web;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MainApp {
public static void main(String args[]){
SpringApplication.run(MainApp.class, args);
}
}
스프링 부트는 main 메소드가 선언된 클래스를 기준으로 실행되기 때문에 MainApp 클래스는 이 프로젝트의 메인 클래스이다.
@SprinBootApplication
으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성이 모두 자동으로 설정된다.
🎲@SpringBootApplication
@SpringBootApplication
은 자동 설정을 해주기 위한 기본 어노테이션으로, 코드를 열어보면 아래와 같다.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
// 중략..
}
여기서 중요한 것은 스프링 고유 어노테이션 @EnableAutoConfiguration, @ComponentScan, @SpringBootConfiguration이다.
🎲EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// 중략..
}
스프링 부트의 Application Context 설정을 자동으로 수행한는 어노테이션으로,META-INF/spring.factories
에 정의되어 있는 configuration
대상 클래스들을 빈으로 등록해준다.
🧩하지만, 어째서인지 내가 만든 스프링 부트 gradle 프로젝트에선 META-INF가 보이지 않았다. 그래서 다른 블로그의 글을 참고해서 작성했다.
spring.factories를 열어 보면, 엄청나게 많은 클래스들이 스프링 부트 기본 auto configuration 대상으로 나열이 되어 있다.
// ...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
// ...
이 리스트에 있는 클래스들은 @Configuration 어노테이션이 없어도 자동으로 빈으로 등록된다. 추가로 개발자가 직접 이 spring.factories에 클래스를 적어 넣으면 그 클래스 역시 auto configuration 대상에 포함된다.
🎲ComponentScan
@Component 어노테이션 및 streotype(@Service, @Repository, @Controller)어노테이션이 부여된 클래스들을 자동으로 Scan하여 Bean으로 등록해주는 역할을 하는 어노테이션이다.
main 메소드에서 실행하는 SpringApplication.run으로 인해 내장 WAS;Web Application Server를 실행한다. 내장 WAS란 별도로 외부에 WAS를 두지 않고 Application을 실행할 때 내부에서 WAS를 실행하는 것을 이야기 한다. 이렇게 되면 항상 서버에 Tomcat과 같은 외부 WAS를 설치할 필요가 없고, 스프링 부트로 만들어진 Jar 파일(실행 가능한 Java 패키징 파일)로 실행하면 된다.
꼭 스프링 부트에서만 내장 WAS를 사용할 수 있는 것은 아니지만, 스프링 부트에서는 내장 WAS를 사용하는 것을 권장하고 있다. 이유는 ‘언제 어디서나 같은 환경에서 스프링 부트를 배포’할 수 있기 때문이다. 외장 WAS를 쓴다고 하면 모든 서버는 WAS의 종류와 버전, 설정을 일치시켜야만 한다. 새로운 서버가 추가되면 모든 서버가 같은 WAS 환경을 구축해야만 한다. 이렇게 될 경우 실수할 여지도 많고 시간이 많이 소모되기 때문에 큰 작업이 될 수도 있다. 하지만 이렇게 내장 WAS를 사용할 경우 이 문제를 모두 해결할 수 있다.
Application 클래스에 대한 설명이 끝났으니, 테스트를 위한 Controller를 만들어 보자. 이번에는 현재 패키지 하위에 controller라는 패키지를 만들어 보겠다. 방법은 위와 동일하다. 앞으로 컨트롤러와 관련된 클래스들은 모두 이 패키지에 담겠다. 그리고 테스트해 볼 컨트롤러 클래스를 생성하자 클래스의 이름은 HelloController로 지정하겠다.
package com.webservice.book.web.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello";
}
}
@RestController : 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어 준다. 예전에는 @ResponseBody를 각 메소드마다 선언했던 것을 한 번에 사용할 수 있게 해준 것이라 생각하자
@GetMapping : HTTP Method인 Get의 요청을 받을 수 있는 API를 만들어 준다. 예전에는 @RequestMapping(method = RequestMethod.GET)으로 사용되었다. 이제 이 프로젝트는 /hello로 요청이 오면 문자열 hello를 반환하는 기능을 가지게 되었다.
작성한 코드가 제대로 작동하는 지 테스트를 하겠다. WAS를 실행하지 않고, 테스트 코드로 먼저 검증해보겠다. src/test/java 디렉토리에 앞에서 생성했던 패키지를 그대로 다시 생성하자 그리고 테스트 코드를 작성할 클래스를 생성한다. 일반적으로 테스트 클래스는 대상 클래스 이름에 Teset를 붙인다. 그러므로 여기서는 HelloControllerTest로 생성한다.
package com.webservice.book.web.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void returnHello() throws Exception{
String hello = "hello";
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string(hello));
}
}
@RunWith(SpringRunner.class)
- 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시킨다.
- 여기서는 SPringRunner라는 스프링 실행자를 사용한다.
- 즉, 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 한다.
@WebMvcTest
- 여러 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션이다.
- 선언할 경우 @Controller, @ControllerAdvice 등을 사용할 수 있다.
- 단, @Service, @Component, @Repository 등은 사용할 수 없다.
- 여기서는 컨트롤러만 사용하기 때문에 선언한다.
@Autowired
- 스프링이 관리하는 빈(Bean)을 주입 받는다.
private MockMvc mvc
- 웹 API를 테스트할 때 사용한다.
- 스프링 MVC 테스트의 시작점이다.
- 이 클래스를 통해 HTTP GET, POST등에 대한 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”를 리턴하기 때문에 이 값이 맞는 지 검증한다.
Leave a comment