[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"));
	}
}




실행시켜보겠습니다~!


image




테스트 통과되었네요~!


read 메소드 테스트




그 다음 테스트할 메소드는 read 메소드입니다~!


image



게시판을 보면 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"));
	}
}




실행시켜 보겠습니다!


image




테스트 통과되었습니다~!


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"));
	}
}




image




테스트 통과입니다~!