[JUnit] 2.Controller Test
Controller Test
이번 장에서는 [Spring] 26.SpringProject-검색 기능(3) 까지 진행된 스프링 프로젝트의 Controller를 JUnit 으로 Test해보겠습니다!
물론 지금까지 BoardController의 메소드의 return 값이 json 데이터가 아닌 jsp파일이기에 메소드 실행 후의 return 값이 예측되는 값과 일치하는지에 대한 구체적인 테스트는 진행할 수 없지만,
그래도 컨트롤러를 테스트해본다는 것에 일단 의의를 두겠습니다!
먼저, 저희가 테스트할 BoardController입니다!
//BoardController.java
package com.gguri.swp.controller;
import java.util.List;
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.gguri.swp.domain.BoardVO;
import com.gguri.swp.domain.Criteria;
import com.gguri.swp.domain.PageMaker;
import com.gguri.swp.service.BoardService;
@Controller
@RequestMapping("/board/*")
public class BoardController {
private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
@Inject
private BoardService service;
@RequestMapping(value = "/register", method = RequestMethod.GET)
public void registerGET(BoardVO board,
@ModelAttribute("cri") Criteria cri,
Model model) throws Exception{
logger.info("register get.....");
}
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerPOST(BoardVO board,
Criteria cri,
RedirectAttributes rttr) throws Exception{
logger.info("register post.....");
logger.info(board.toString());
service.regist(board);
rttr.addFlashAttribute("result", "registerOK");
rttr.addAttribute("page", 1);
rttr.addAttribute("perPageNum", cri.getPerPageNum());
return "redirect:/board/listPage";
}
@RequestMapping(value = "/dummy")
public String dummyPOST(RedirectAttributes rttr) throws Exception{
logger.info("dummy post.....");
service.dummy();
rttr.addFlashAttribute("result", "registerOK");
return "redirect:/board/listPage";
}
@RequestMapping(value = "/read", method = RequestMethod.GET)
public void read(@RequestParam("bno") Integer bno,
@ModelAttribute("cri") Criteria cri,
Model model) throws Exception{
logger.info("read GET...");
BoardVO board = service.read(bno);
model.addAttribute(board);
}
@RequestMapping(value = "/update", method = RequestMethod.GET)
public void updateGET(@RequestParam("bno") Integer bno,
@ModelAttribute("cri") Criteria cri,
Model model) throws Exception{
logger.info("update GET");
BoardVO board = service.read(bno);
model.addAttribute(board);
}
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String updatePOST(BoardVO board,
Criteria cri,
RedirectAttributes rttr) throws Exception{
logger.info("update POST");
service.modify(board);
rttr.addFlashAttribute("result","saveOK");
rttr.addAttribute("page", cri.getPage());
rttr.addAttribute("perPageNum", cri.getPerPageNum());
rttr.addAttribute("searchType", cri.getSearchType());
rttr.addAttribute("keyword", cri.getKeyword());
rttr.addAttribute("bno", board.getBno());
return "redirect:/board/read";
}
@RequestMapping(value = "/remove", method = RequestMethod.GET)
public String remove(@RequestParam("bno") Integer bno,
Criteria cri,
RedirectAttributes rttr) throws Exception{
logger.info("remove");
service.remove(bno);
rttr.addFlashAttribute("result","removeOK");
rttr.addAttribute("page", cri.getPage());
rttr.addAttribute("perPageNum", cri.getPerPageNum());
rttr.addAttribute("searchType", cri.getSearchType());
rttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/board/listPage";
}
@RequestMapping(value = "/listPage", method = RequestMethod.GET)
public void listPage(Criteria cri, Model model) throws Exception{
logger.info("listPage");
List<BoardVO> boards = service.listPage(cri);
model.addAttribute("list",boards);
PageMaker pageMaker = new PageMaker(cri);
int totalCount = service.getTotalCount(cri);
pageMaker.setTotalCount(totalCount);
model.addAttribute("pageMaker", pageMaker);
}
}
테스트를 다 하지는 않고, 메소드 몇 개만 해보겠습니다!
listPage 메소드 테스트
먼저, 테스트할 메소드는 listPage 메소드입니다~!
//BoardController.java
package com.gguri.swp.controller;
...
@Controller
@RequestMapping("/board/*")
public class BoardController {
private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
@Inject
private BoardService service;
...
@RequestMapping(value = "/listPage", method = RequestMethod.GET)
public void listPage(Criteria cri, Model model) throws Exception{
logger.info("listPage");
List<BoardVO> boards = service.listPage(cri);
model.addAttribute("list",boards);
PageMaker pageMaker = new PageMaker(cri);
int totalCount = service.getTotalCount(cri);
pageMaker.setTotalCount(totalCount);
model.addAttribute("pageMaker", pageMaker);
}
}
그리고 JUnit Test 파일 BoardControllerTest.java를 만들어줍니다!
//BoardControllerTest.java
package com.gguri.swp.controller;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.handler;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import javax.inject.Inject;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
//Runner 클래스(테스트 메소드를 실행하는 클래스) 를 SpringJUnit4ClassRunner로 함
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
//location 속성 경로에 있는 xml 파일을 이용해서 스프링이 로딩됨
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/**/*.xml")
public class BoardControllerTest {
private static final Logger logger = LoggerFactory.getLogger(BoardControllerTest.class);
//웹 응용 프로그램의 구성을 제공하는 인터페이스
@Inject
private WebApplicationContext wac;
//톰캣을 작동시키지 않아도 컨트롤러 테스트를 진행하게 해줌
private MockMvc mockmvc;
@Before
public void setup() {
//스프링이 준 WebApplicationContext를 이용해서 mockmvc를 생성
this.mockmvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
logger.debug("setup BoardControllerTest mockMvc...");
}
@Test
public void testListPage() throws Exception {
this.mockmvc.perform(get("/board/listPage").param("page","2"))
.andDo(print())
//정상 처리 되는지 확인
.andExpect(status().isOk())
//담당 컨트롤러가 BoardController인지 확인
.andExpect(handler().handlerType(BoardController.class))
//메소드 이름이 listPage인지 확인
.andExpect(handler().methodName("listPage"));
}
}
실행시켜보겠습니다~!
테스트 통과되었네요~!
read 메소드 테스트
그 다음 테스트할 메소드는 read 메소드입니다~!
게시판을 보면 252번 게시물은 존재하고, 253번 게시물은 존재하지 않습니다~
따라서 252번 게시물을 조회하면 정상처리 되지만, 253번 게시물을 조회하면 404 에러메시지가 나옵니다~!
이것을 테스트하기 위해 read 메소드에서 없는 게시물 번호를 조회하면 404 에러가 뜨게 조치하겠습니다!
안해주면 예외를 전부 [Spring] 18.SpringProject-예외처리에서 만든 CommonExceptionAdvice.java가 처리하기 때문에 정상 처리가 됩니다!
//BoardController.java
package com.gguri.swp.controller;
...
@Controller
@RequestMapping("/board/*")
public class BoardController {
private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
@Inject
private BoardService service;
...
@RequestMapping(value = "/read", method = RequestMethod.GET)
public void read(@RequestParam("bno") Integer bno,
@ModelAttribute("cri") Criteria cri,
HttpServletResponse response,
Model model) throws Exception{
logger.info("read GET...");
BoardVO board = service.read(bno);
if(board == null) {
response.sendError(404);
}
model.addAttribute(board);
}
...
}
그 다음 BoardControllerTest.java에 testRead 메소드와 testRead2 메소드를 추가해줍니다!
//BoardControllerTest.java
package com.gguri.swp.controller;
...
//Runner 클래스(테스트 메소드를 실행하는 클래스) 를 SpringJUnit4ClassRunner로 함
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
//location 속성 경로에 있는 xml 파일을 이용해서 스프링이 로딩됨
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/**/*.xml")
public class BoardControllerTest {
private static final Logger logger = LoggerFactory.getLogger(BoardControllerTest.class);
//웹 응용 프로그램의 구성을 제공하는 인터페이스
@Inject
private WebApplicationContext wac;
//톰캣을 작동시키지 않아도 컨트롤러 테스트를 진행하게 해줌
private MockMvc mockmvc;
@Before
public void setup() {
//스프링이 준 WebApplicationContext를 이용해서 mockmvc를 생성
this.mockmvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
logger.debug("setup BoardControllerTest mockMvc...");
}
@Ignore
public void testListPage() throws Exception {
this.mockmvc.perform(get("/board/listPage").param("page","2"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(handler().handlerType(BoardController.class))
.andExpect(handler().methodName("listPage"));
}
@Test
public void testRead() throws Exception{
this.mockmvc.perform(get("/board/read").param("bno", "252"))
.andDo(print())
//252번 게시물은 존재하므로 정상처리 예측
.andExpect(status().isOk())
.andExpect(handler().handlerType(BoardController.class))
//메소드 이름이 read인지 확인
.andExpect(handler().methodName("read"));
}
@Test
public void testRead2() throws Exception{
this.mockmvc.perform(get("/board/read").param("bno", "253"))
.andDo(print())
//253번 게시물은 없기에 404에러 발생 예측
.andExpect(status().is4xxClientError())
.andExpect(handler().handlerType(BoardController.class))
//메소드 이름이 read인지 확인
.andExpect(handler().methodName("read"));
}
}
실행시켜 보겠습니다!
테스트 통과되었습니다~!
update 메소드 테스트
마지막으로 테스트할 것은 update 메소드입니다!
//BoardController.java
package com.gguri.swp.controller;
...
@Controller
@RequestMapping("/board/*")
public class BoardController {
private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
@Inject
private BoardService service;
...
@RequestMapping(value = "/update", method = RequestMethod.POST)
public String updatePOST(BoardVO board,
Criteria cri,
RedirectAttributes rttr) throws Exception{
logger.info("update POST");
service.modify(board);
rttr.addFlashAttribute("result","saveOK");
rttr.addAttribute("page", cri.getPage());
rttr.addAttribute("perPageNum", cri.getPerPageNum());
rttr.addAttribute("searchType", cri.getSearchType());
rttr.addAttribute("keyword", cri.getKeyword());
rttr.addAttribute("bno", board.getBno());
return "redirect:/board/read";
}
...
}
BoardControllerTest.java에 testUpdate 메소드를 추가해주겠습니다!
//BoardControllerTest.java
package com.gguri.swp.controller;
...
//Runner 클래스(테스트 메소드를 실행하는 클래스) 를 SpringJUnit4ClassRunner로 함
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
//location 속성 경로에 있는 xml 파일을 이용해서 스프링이 로딩됨
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/**/*.xml")
public class BoardControllerTest {
private static final Logger logger = LoggerFactory.getLogger(BoardControllerTest.class);
//웹 응용 프로그램의 구성을 제공하는 인터페이스
@Inject
private WebApplicationContext wac;
//톰캣을 작동시키지 않아도 컨트롤러 테스트를 진행하게 해줌
private MockMvc mockmvc;
@Before
public void setup() {
//스프링이 준 WebApplicationContext를 이용해서 mockmvc를 생성
this.mockmvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
logger.debug("setup BoardControllerTest mockMvc...");
}
...
@Ignore
public void testRead2() throws Exception{
this.mockmvc.perform(get("/board/read").param("bno", "253"))
.andDo(print())
.andExpect(status().is4xxClientError())
.andExpect(handler().handlerType(BoardController.class))
.andExpect(handler().methodName("read"));
}
@Test
public void testUpdate() throws Exception{
this.mockmvc.perform(post("/board/update")
.param("bno", "2")
.param("title", "수정")
.param("content","수정")
)
.andDo(print())
//listPage로 리다이렉트 되기에 302 메시지를 예측
.andExpect(status().is3xxRedirection())
.andExpect(handler().handlerType(BoardController.class))
.andExpect(handler().methodName("updatePOST"));
}
}