Spring MVC Test
- The Spring MVC Test framework
- Spring MVC code를 테스트하기 위한 일등 클래스?(first class)를 제공
- JUnit, TestNG 또는 다른 테스트 프레임워크와 같이 사용 API를 제공
- 서블릿 컨테이너를 구동하지 않아도 된다.
- spring-test module의 Servlet API mock objects 기반위에서 만들어 졌다
- DispatcherServlet을 사용
- full Spring MVC runtime behavior를 제공
- TestContext framework을 이용하여 Spring configuration을 로딩
- 컨트롤러를 수동으로 초기화하고 한번씩 테스트되는 a standalone mode도 가능
- client-side
- RestTemplate을 이용한 클라이언트 사이드 테스트 지원
- 서버 구동없이 서버 응답을 mock한다.
- Spring Boot
- 서버를 구동시켜 테스트할 수 있는 full, end-to-end integration test를 제공
pom설정
Sample code
WebApplicationContext
- XML configuration 파일로 부터 Spring configuration을 로딩(TestContext framework)
MockMvc instance
- 요청(request)을 날리고 응답(response)을 검증
- 결과를 검증하는데 많은 옵션이 존재함
- MockMvc instance를 생성하는데 2가지 옵션이 존재
webAppContextSetup 방식
- TestContext framework을 통해 Spring MVC configuration을 로딩
- Spring configuration을 로딩하여 WebApplicationContext을 MockMvc instance을 생성할 test에 주입
- Spring MVC configuration을 로딩하는 방법(1번)이 좀 더 완전한 통합 테스트를 이루어 낼 수 있다.
- TestContext framework이 Spring configuration을 캐쉬하기 때문에, 많은 테스트가 있어도 빠르게 테스트를 수행할 수 있다.
- 또한, mock services를 Spring configuration을 톻애 controller에 주입할 수 있다. (웹 레이어에 집중해서 테스트하기 위함)
standaloneSetup 방식
- Spring configuration을 로딩하지 않고 controller instance를 수동으로 생성
- 한번에 하나의 controller를 테스트하는 방식으로 좀 더 unit test에 가깝다.
Static Imports
- 이클립스에서 단위 테스트 코드를 만들 때 static method를 매번 import 해야함 import할 때 자주 사용하는 단축키인 Ctrl + Shift + O도 사용할 수 없어 불편
- 다음과 같이 설정하고 단위 테스트 코드를 만들면 편리하다.
- 이클립스에서 "favorite static members" 로 add type 해서 사용하면 편함 ( Eclipse preferences under Java → Editor → Content Assist → Favorites )
- 추가하면 좋은 타입 org.hamcrest.CoreMatchers, org.hamcrest.Matchers, org.junit.Assert org.springframework.test.web.servlet.request.MockMvcRequestBuilders org.springframework.test.web.servlet.result.MockMvcResultMatchers
- 자동 import static 사용하기 위 과정을 다 마치면 빨간표시에 import 구문 추가가 보인다.
HTTP 요청(Request) 수행하기
query parameters in URI template
- URI 템플릿으로 작성된 query params는 디코드 된다
Servlet request parameters (form parameter)
- param(…?) 메소드를 통해 작성된 request parameters 디코드 되어져 있다고 여겨진다
request URI에서 context path 와 Servlet path 의 분리
mockMvc.perform(get("/app/main/hotels/{id}").contextPath("/app").servletPath("/main"))
매번 위와 같이 작성하기 번거롭다면 default request properties를 작성하고 특정 값을 오버라이드 해서 사용할 수도 있음
public class MyWebTests {
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = standaloneSetup(new AccountController())
.defaultRequest(get("/")
.contextPath("/app").servletPath("/main")
.accept(MediaType.APPLICATION_JSON).build();
}
위 코드는 the MockMvc instance를 통해 수행되는 모든 request에 적용된다. same property가 명시되면 기본값을 오버라이딩해서 사용할 수 있다. 기본 요청에서 HTTP method and URI 값은 매 요청마다 재설정될 것이기에 중요하지 않다.
Defining Expectations (응답 예상하기)
요청 수행 후 결과 예상은 하나 이상의 .andExpect(..) 코드를 붙여서 정의할 수 있다
mockMvc.perform(get("/accounts/1")).andExpect(status().isOk());
MockMvcResultMatchers.*
에서 수많은 expectations를 제공하고 더 자세한 nested 코드를 제공한다.
2가지 카테고리로 나눌 수 있다
첫번째는 response status, headers, and content와 같은 응답의 properties 를 검증하는 assertions 이다.
두번째는 response 범위를 벗어난 Spring MVC specific aspects를 검사하는 것이다. 예를들면, 요청이 어떤 컨트롤러 메소드를 탔는지, Exception이 발생했고 처리됐는지, 모델(model)의 내용은 어떤것이 있는지, 어떤 뷰(view)가 선택됐는지, 어떤flush attribute가 추가됐는지 등이다. 이것은 요청과 세션의 attributes와 같은 Servlet specific aspects 를 검사하는데 사용된다
Response dump(응답 덤프)
테스트를 작성할 때 많은 경우 요청의 응답을 덤프(dump)하는것이 유용하다.
print()
MockMvcResultHandlers에서 제공하는 static import 중 print()를 사용할 수 있다. 요청을 처리하다가 an unhandled exception이 발생하지 않는다면, print() 메소드는 모든 가능한 결과 데이터를 System.out 표준 출력으로 나타낼 줄 것이다 Spring Framework 4.2 에서 log() 메소드와 추가적으로 두가지 print 메소드를 소개했었다 하나는 OutputStream을 인자로 받아들이는 것이고 하나는 Writer를 인자로 받아 들이는 것이다. 즉, 각각 print(System.err), print(myWriter)처럼 사용할 수 있다.
log()
결과 데이터를 프린트 대신에 로그로 남기고 싶을 때, 간단히 log() 메소드를 사용하면 the org.springframework.test.web.servlet.result logging category에 결과데이터를 로그로 남길 수도 있다 단, 디버그 모드로 지정해야만 하며, log4j2와 같은 로그 설정에 의해 지정된 file로 출력하게 된다.
MvcResult 객체
어떤 경우 결과값에 직접 접근하거나 검증이 불가한 항목을 검증하기 위하여 MvcResult 객체를 제공한다
MvcResult mvcResult = mockMvc.perform(post("/persons")).andExpect(status().isOk()).andReturn();
위와 같이 모든 expectations 끝에다가 andReturn()를 붙이면 MvcResult 객체를 리턴 받을 수 있다.
expectations 반복
모든 테스트가 같은 expectations 을 반복한다면 공통 expectations 을 작성하여 모두 적용시킬 수 있다 MockMvc instance를 생성할 때 .alwaysExpect()를 사용하여 공통 expectations 코드를 적용한다.
standaloneSetup(new SimpleController())
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json;charset=UTF-8"))
.build()
주의! common expectations 은 항상 적용된다. MockMvc instance를 분리하여 생성하지 않는 한 오버라이드 되지 않는다.
Spring HATEOAS
JSON/XML 응답 contents가 Spring HATEOAS를 사용하여 생성한 hypermedia links를 포함하면 링크는 JsonPath/XPath expressions를 사용하여 검증가능하다
Servlet Filter 서블릿 필터 등록
MockMvc instance를 설정할 때, .addFilters()를 사용하여 하나 이상의 Servlet Filter instance를 등록할 수 있다.
mockMvc = standaloneSetup(new PersonController()).addFilters(new CharacterEncodingFilter()).build();
등록된 필터는 spring-test의 MockFilterChain을 통해 작동되며 마지막 필터는 DispatcherServlet에게 위임한다
Sample
예제를 모아둔 github이다 https://github.com/spring-projects/spring-framework/tree/master/spring-test/src/test/java/org/springframework/test/web/servlet/samples
zip 다운로드 후에 아래 경로에서 파일을 뒤적뒤적(Browse)해보자 spring-framework-master\spring-framework-master\spring-test\src\test\java\org\springframework\test\web\servlet\samples
SampleShowcase
간단한 예제로 Spring MVC web framework으로 할 수 있는 기능을 데모로 보여준다. 코드 안에는 Spring MVC Test에 기반한 테스트 코드가 포함되어 있다.
/spring-mvc-showcase-master/src/test/java/org/springframework/samples
The simplest possible @Controller, Mapping Requests, Obtaining Request Data, Generating Responses Message Converters, Rendering Views, Type Conversion, Validation, Forms, File Upload, Exception Handling
https://github.com/spring-projects/spring-mvc-showcase 위 경로에서 다운(zip)받아 압축을 푼 뒤, cmd 창으로 디렉토리로 이동 후 다음 명령어를 실행하여 구동하면 된다. (메이븐 설치 및 설정이 되어 있어야 함)
mvn tomcat7:run
접속 http://localhost:8080/spring-mvc-showcase/