오전에 업무로 부랴부랴 시간을 보내고 오후부터 저번 스터디에서 발표했던 타칭 ORM 으로 불리우는 GenericDao에 주석을 정리하면서 시간을 보내던 중 HelloIS님으로부터 메시지가 왔다.

간단히 줄이자면 @Controller 에 대한 테스트를 방법을 찾아보고 계신다는 것이다.

얼마전에 whiteship님의 블로그에 포팅된 스프링 2.5 @MVC 컨트롤러 테스트에 관한 글도 비슷한 맥락에서 방법을 찾아보고 계신것 같았다. 덧글 중 토비님께서는 프레임워크의 테스트를 믿고 나가는게 맞지 않느냐를 말씀도 있으셨다.

테스트가 필요할까? 필요하지 않을까? 내 생각도 아직까지 정리가 되지 않고 있다. 애초에 프레임워크를 쓰는 이유 중 하나인 높은 생산성도 있을텐데 믿지 못하고 일일히 테스트를 한다면 어느 세월에 다 할것인가 싶기도 하지만 은근히 궁금하다. ^^;;

그리고 개발자도 사람인 이상 오타는 분명이 있을테니 @RequestMapping 어노테이션에 엉뚱한 URL 을 적어두고 딴데서 삽질하는 일이 있을수도 있지 않은가! -0-

그럼 어떻게 테스트를 할 수 있을까?

집에오면서 생각한게 가장 단순하게 생각하면 스프링 @MVC 는 DispatcherServlet 에서부터 시작된다는 것이다.

그럼 테스트 코드에서 DispatcherServlet 을 생성해서 사용하면 되지 않을까?

그래서 우선 다음과 같은 @Controller 을 만들었다.

@Controller
@RequestMapping("/hello/hello.htm")
public class HelloController {
   
    @RequestMapping(method=RequestMethod.GET)
    public String helloGet(HttpServletRequest req, HttpServletResponse res, ModelMap modelMap){
        modelMap.addAttribute("hello", "hi~ my name is GET");
        return "hello/get";
    }
   
    @RequestMapping(method=RequestMethod.POST)
    public String helloPost(HttpServletRequest req, HttpServletResponse res, ModelMap modelMap){
        modelMap.addAttribute("hello", "hi~ my name is POST");
        return "hello/post";
    }
}

그리고 설정 파일을 다음과 같이 만들었다.

<context:annotation-config />
<context:component-scan base-package="controllertest.controller" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
</context:component-scan>

<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"
          p:alwaysUseFullPath="true" />
         
<bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/view/jsp/"
          p:suffix=".jsp" />

마지막으로 테스트 코드를 다음과 같이 작성했다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:/**/ApplicationContext.xml"})
public class HelloControllerTest {
   
    @Autowired
    ApplicationContext applicationContext;
   
    DispatcherServlet dispatcher;
   
    @SuppressWarnings("serial")
    public HelloControllerTest(){
        this.dispatcher = new DispatcherServlet() {
            protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
                GenericWebApplicationContext wac = new GenericWebApplicationContext();
                wac.setParent(applicationContext);
                wac.refresh();
                return wac;
            }
        };
        try {
            this.dispatcher.init(new MockServletConfig());
        } catch (ServletException e) {
            e.printStackTrace();
        }

    }
   
    @Test
    public void helloGet() throws Exception {     
       
        MockHttpServletRequest req = new MockHttpServletRequest("GET", "/hello/hello.htm");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(200, res.getStatus());
       
        // Attribute 검사
        Object obj = req.getAttribute("hello");
        Assert.assertNotNull(obj);
       
        System.out.println(String.format("AttributeName : hello, Value : %s", obj));
       
        // 포워드 주소...
        System.out.println(res.getForwardedUrl());
    }
   
    @Test
    public void helloPost() throws Exception {

        MockHttpServletRequest req = new MockHttpServletRequest("POST", "/hello/hello.htm");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(200, res.getStatus());
        // Attribute 검사
        Object obj = req.getAttribute("hello");
        Assert.assertNotNull(obj);
        System.out.println(String.format("AttributeName : hello, Value : %s", obj));
        // 포워드 주소...
        System.out.println(res.getForwardedUrl());
    }
   
    @Test
    public void hello() throws Exception {
       
        MockHttpServletRequest req = new MockHttpServletRequest("POST", "/hello/hello.ht");
        MockHttpServletResponse res = new MockHttpServletResponse();
       
        dispatcher.service(req, res);
       
        // HTTP 상태 검사
        Assert.assertEquals(404, res.getStatus());
    }   
}

위와 같이 작성 후 테스트를 실행하면 다음과 같은 결과를 얻을 수 있었다.

AttributeName : hello, Value : hi~ my name is GET
/WEB-INF/view/jsp/hello/get.jsp

AttributeName : hello, Value : hi~ my name is POST
/WEB-INF/view/jsp/hello/post.jsp

마지막 테스트 함수의 경우 올바른 경로를 입력하지 않았기 때문에 HTTP 상태는 404(파일없음)이 나오는 것이다.

이것이 올바른 방법으로 테스트가 되었고 결과값이 나온건이 대해서는 아직 확신이 없다.
Posted by Arawn Trackback 1 : Comment 3

댓글을 달아 주세요

  1. addr | edit/del | reply Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.11.04 22:22

    우와.. 잘 참고하겠습니다. :)

  2. addr | edit/del | reply Favicon of https://helols.tistory.com BlogIcon is윤군 2008.11.04 23:33 신고

    헉;;; 결국 DispatcherServlet 까지 올라 와버렸네요;;ㅋㅋ 전 이놈을 어떻게 생성하나;;
    이러고 고민하고 있었는데;ㅜ 일단 참고 하여서;; 다시 작성한번 해보겠습니다~
    괜히 저의 삽질로 인해 피해가 간건 아닌지;; ㅜㅜ 탱삼합니다^^

  3. addr | edit/del | reply Arawn 2008.11.05 17:50

    ㅎㅎ... 완전 무식한 방법이라... 테스트인지 아닌지.. 판단 내리기도 어렵네요 ^^: