MockMvc Test
MockMvc를 이용한 컨트롤러 테스트
Spring과 연동하면 Spring Bean은 모두 테스트가 가능하다. 하지만 컨트롤러의 경우 요청과 존재해야 하며, 주입할 수 있는 객체가 아니기 때문에 테스트가 불가하다. Spring Test에서는 MockMvc
객체를 이용하여 가상의 요청을 만들고 그에 따른 실행 결과를 테스트 할 수 있다.
테스트 컨트롤러를 생성한다.
src/main/java : com.hakademy.spring11.controller.TestController
package com.hakademy.spring11.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class TestController {
@GetMapping("/test1")
@ResponseBody
public String test1() {
return "test1 complete";
}
}
이 컨트롤러가 정상적으로 작동하는지 테스트 하는 방법은 2가지가 있다.
서버에 프로젝트를 올려 구동한 뒤 브라우저를 이용하여 확인한다.
MockMvc
를 이용하여 테스트를 수행한다.
MockMvc
를 이용하는 테스트 케이스를 생성한다.
src/test/java : com.hakademy.spring11.Test
package com.hakademy.spring11;
public class Test06 {
}
다른 Spring과 연동 없이 단독으로 TestController 하나만 테스트 하기 위해 StandAlone 형태로 MockMvc
인스턴스를 생성한다.
MockMvc mockMvc;
@Before
public void prepare() {
mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
}
완성된 MockMvc
객체를 이용하여 테스트를 수행한다.
@Test
public void test() throws Exception {
mockMvc.perform(get("/test1"))
.andDo(print())
.andExpect(status().is2xxSuccessful())
.andReturn();
}
테스트 수행 시 다음과 같은 결과를 확인할 수 있다.

MockHttpServletRequest:
HTTP Method = GET
Request URI = /test1
Parameters = {}
Headers = {}
Handler:
Type = com.hakademy.spring11.controller.TestController
Method = public java.lang.String com.hakademy.spring11.controller.TestController.test1()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[text/plain;charset=ISO-8859-1], Content-Length=[14]}
Content type = text/plain;charset=ISO-8859-1
Body = test1 complete
Forwarded URL = null
Redirected URL = null
Cookies = []
MockMvc 명령 정리
MockMvc
를 이용하여 테스트를 수행할 때 필요한 명령들은 다음과 같다.
.perform() : 요청을 수행하고 추가 조치를 수행할 수 있는
ResultActions
데이터 반환.andDo() : 수행할 일반적인 행동을 설정합니다.
.andExpect() : 성공 상황을 설정(단정)합니다.
.andReturn() : 결과에 대한 정보들을
MvcResult
형태로 반환
perform
perform
은 요청을 수행하기 위한 기본 명령이다.
내부에는 MockMvcRequestBuilders
클래스의 명령들을 사용하여 수행할 작업을 지정해줄 수 있다.
MockMvcRequestBuilders
는 static import로 생략이 가능하며 주요 명령으로는 다음과 같다.
get(url) : url에 대한
GET
방식의 요청을 수행post(url) : url에 대한
POST
방식의 요청을 수행put(url) : url에 대한
PUT
방식의 요청을 수행delete(url) : url에 대한
DELETE
방식의 요청을 수행patch(url) : url에 대한
PATCH
방식의 요청을 수행
요청 방식을 결정한 뒤에는 다음과 같이 추가 작업을 설정할 수 있다.
.param(name, value) : 요청 파라미터를 추가(name=value)
.accept(media) : accept 설정 수행
.characterEncoding(enc) : 요청 인코딩을 enc로 설정
.cookies(cks) : 요청에 쿠키를 추가
.contentType(type) : 요청의 MIME-TYPE을 type으로 설정
.requestAttr(name, value) : 요청에 Attribute를 추가
.session(mock) : 세션 추가
.sessionAttr(name, value) : 세션에 Attribute를 추가
.header(name, value) : 헤더 추가
.locale(locale) : 요청 언어 설정
andDo
andDo
는 요청과 함께 수행할 작업을 지정할 때 사용한다.
사용할 수 있는 명령의 종류는 MockMvcResultHandlers
에 정의되어 있으며 다음과 같다.
.print() : 지정된 대상에 메시지 출력
.log() : 로그 형태의 출력
andExpect
andExpect
는 기대되는 상황에 대해서 정의할 때 사용한다.
복수개 설정이 가능하며, 상황에 맞지 않을 경우에는 테스트가 실패한다.
사용할 수 있는 명령의 종류는 MockMvcResultMatchers
에 정의되어 있으며 다음과 같다.
.content() : Response Body를 검증할 때 사용
.cookie() : 쿠키를 검증할 때 사용
.flash() : Flash Attribute를 검증할 때 사용
.forwardedUrl(url) : forward된 URL이 url인지 검증할 때 사용
.forwardedUrlPattern(pattern) : forwared된 URL이 pattern 형태인지 검증할 때 사용
.handler() : 처리 핸들러를 검증할 때 사용
.header() : header를 검증할 때 사용
.redirectedUrl(url) : redirect된 URL이 url인지 검증할 때 사용
.redirectedUrlPattern(pattern) : redirect된 URL이 pattern 형태인지 검증할 때 사용
.request() : 요청을 검증할 때 사용
.status() : 상태를 검증할 때 사용
.view() : view를 검증할 때 사용
andReturn
andReturn
은 테스트 수행 후 MvcResult
형태의 객체를 반환한다.
Request
Response
Exception
Interceptor
AsyncResult
등의 정보를 확인할 수 있다.
MockMvc를 이용한 WebApplication 테스트
Standalone 방식의 테스트로는 ViewResolver 등 연관된 기능들을 포함한 테스트를 구현하기 어렵다.
다음 매핑을 TestController
에 추가한 뒤 테스트를 수행해서 원인을 찾아본다.
src/main/java : com.hakademy.spring11.TestController
@GetMapping("/test2")
public String test2() {
return "test2";
}
@ResponseBody가 없기 때문에 반환값인 test2
는 ViewResolver와 결합하여 /WEB-INF/views/test2.jsp
로 인식되어야 한다.
테스트를 수행하여 정상적으로 처리되는지 확인해본다.
src/test/java : com.hakademy.spring11.Test07
package com.hakademy.spring11;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.hakademy.spring11.controller.TestController;
public class Test07 {
MockMvc mockMvc;
@Before
public void prepare() {
mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
}
@Test
public void test() throws Exception {
mockMvc.perform(get("/test2"))
.andDo(print())
.andExpect(status().is2xxSuccessful())
.andReturn();
}
}
테스트를 수행하면 오류가 발생하며, 오류 로그는 다음과 같이 나온다.
javax.servlet.ServletException: Circular view path [test2]: would dispatch back to the current handler URL [/test2] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)
오류 메시지의 내용은 ViewResolver setup을 확인하라는 것이다. 즉, ViewResolver를 사용할 수 없다는 것인데, 이 때는 Spring의 환경과 연동한 테스트를 수행하여야 한다.
Spring과 연동한 테스트를 수행하고 싶을 경우 다음과 같이 테스트를 구성해야 한다.
src/test/java : com.hakademy.spring11.Test08
package com.hakademy.spring11;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"
})
public class Test08 {
@Autowired
WebApplicationContext context;
MockMvc mockMvc;
@Before
public void prepare() {
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@Test
public void test() throws Exception {
mockMvc.perform(get("/test2"))
.andDo(print())
.andExpect(status().is2xxSuccessful())
.andReturn();
}
}
수행하면 테스트가 성공함을 확인할 수 있다.
Standalone 테스트와 비교
Standalone 테스트에서의 변경사항을 확인해보면 다음과 같다.
스프링 환경과의 연동 설정을 수행한다.
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = {
"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"
})
MockMvc
에 환경정보를 설정하기 위해 WebApplicationContext
객체를 연결 생성한다.
MockMvc
에 환경정보를 설정하기 위해 WebApplicationContext
객체를 연결 생성한다.환경이 연동되어 있을 때에만 자동 주입이 되므로 주의한다.
@Autowired
WebApplicationContext context;
MockMvc
객체를 생성할 때 .webAppContextSetup()
명령을 사용한다.
MockMvc
객체를 생성할 때 .webAppContextSetup()
명령을 사용한다.mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
위와 같이 처리할 경우 Spring 요청 처리의 대부분을 확인할 수 있으며, 처리 결과는 다음과 같다.
MockHttpServletRequest:
HTTP Method = GET
Request URI = /test2
Parameters = {}
Headers = {}
Handler:
Type = com.hakademy.spring11.controller.TestController
Method = public java.lang.String com.hakademy.spring11.controller.TestController.test2()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = test2
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = /WEB-INF/views/test2.jsp
Redirected URL = null
Cookies = []
Last updated