on
Spring-Test-MVC 프로젝트 소개
Spring-Test-MVC 프로젝트 소개
이 글에서는 Builder 패턴을 사용해서 스프링 MVC 테스트 코드를 작성하는 방법을 알아봅니다
MockMvcBuilders.standaloneMvcSetup( new TestController()).build() .perform(get("/form")) .andExpect(status().isOk()) .andExpect(content().type("text/plain")) .andExpect(content().string("hello world") );
TestController를 바탕으로 MockMvc 타입의 객체를 만들고 "/form" 요청을 보내서 그 응답을 받아서 HttpStatus 코드가 "200" 이고 , 콘텐츠 타입이 "text/plain"이고 , 응답 본문에 "context" 라는 값이 있는지 확인한다.
TestController controller = new TestController(); MockHttpServletRequest req = new MockHttpRequest(); MockHttpSerlvetResponse res = new MockHttpResponse(); ModelAndView mav = controller.form(req, res); assertThat(res.getStatus(), is(200)); assertThat(res.getContentType(), is(“text/plain”)); assertThat(res.getContentAsString (), is(“content”));
위와 같은 작업을 기존의 Spring에서 제공하는 MockHttpRequest 와 MockHttpResponse 로 작성한다면 다음과 같다.
이 테스트코드는 너무 많은 걸 가정하고 있다. 우선 form() 메서드의 매개변수가 HttpServletRequest와 HttpServletResponse 라고 가정한다. 그러나 이 두 매개변수는 Spring 애노테이션 기반의 MVC 즉 @MVC에 자주 사용하지 않는 매개 변수이다. 오히려 @RequestMapping 과 @ModelAttribute 그리고 Model 타입을 더 자주 사용하기 때문에 더 다양한 테스트 픽스처를 만들어야 한다. 그리고 이 메서드의 결과 타입으로 ModelAndView를 가정하는데 이것 역시 @MVC에서는 보통 View 이름만 반환하고 String 타입을 사용한다. 그마저도 View 이름 생성기를 사용하도록 void 타입을 사용하는 경우도 많다. 위의 테스트는 그히 제한적인 경우만 사용할 수 있는 코드에 지나지 않는다.
Spring-Test-MVC 프로젝트의 목표는 Servlet 컨테이너를 사용하지 않아도 MockHttpServletRequest 와 MockhttpServletResponse를 사용해서 Spring Controller를 쉽고 편하게 테스트하는 방법을 제공하는 것이다.
ItemController에서 참조하는 ItemService 등 모든 객체 레퍼런스가 null 이기 때문에 NullpointerException 이 발생한다.
스프링 TestContext
평범한 계층 구조 아키텍처를 상요한다면 보통은 다음과 같은 구조로 컨트롤러와 서비스, DAO가 연결되어 있다.
컨트롤러에서 서비스를 사용하고 그 서비스에서는 다시 DAO를 사용한다. 이런 상황에서 컨트롤러를 테스트할 때에는 테스트하는 범위를 기준으로 테스트를 크게 두 가지로 나눌 수 있다.
컨트롤러 클래스 단위 테스트, 컨트롤러 클래스 통합 테스트
단위테스트는 테스트하려는 컨트롤러가 참조하는 모든 객체의 Mock 객체를 만들어서 컨트롤러에 주입하고 테스트 하면 된다.
통합은 복잡하다. Spring Bean설정을 사용해서 테스트 용 ApplicationContext를 만들어 빈주입기능을 사용해야 한다. 물론 Spring에는 TestContext라는 기능으로 그런 작업을 지원할 뿐 아니라, 그보다 더 중요한 기능으로 테스트용 ApplicationContext 공유 기능을 제공한다.
Spring에서 기본으로 제공하는 SpringJUnit4ClassRunner를 사용하여 다음 예제와 같이 ApplicationContext 공유 기능을 사용할 수 있다.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("/testContext.xml") public class TestClassA{ // 테스트 코드 }
@RunWith 메서드는 JUnit에서 제공하는 테스트러너 확장 지점이고 , 그 확장 지점을 사용해서 TestContext 기능을 사용하도록 Spring이 SpringJUnit4ClasssRunner 를 제공한다. 그리고 SpringJunit4ClassRunner는 @ContextConfiguration 에 설정한 빈 설정으로 테스트에 사용할 ApplicationContext 를 만들고 빈을 관리한다. 이렇게 하면 테스트에서는 @Autowired나 @Inject 를 사용해서 테스트할 빈을 주입받아 사용할 수 있다.
Spring-Test-MVC와 TestContext 연동
Spring-Test-MVC 프로젝트를 TestContext 기능과 어떻게 연동할 수 있을까?
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration public class ApplicationContextSetupTests { @Autowired ApplicationContext context; @Test public void responseBodyHandler(){ MockMvc mockMvc = MockMvcBuilders.applicationContextMvcSetup(context) .configureWarRootDir("src/test/webapp", false).build(); mockMvc.perform(get("/form")) .andExpect(status().isOk()) .andExpect(status().string("hello")); mockMvc.perform(get("/wrong")) .andExpect(status().isNotFound()); } @Controller static class TestController { @RequestMapping("/form") public @ResponseBody String form(){ return "hello"; } } }
이 테스트 클래스에 들어있는 TestController 클래스가 위의 Spring 설정 파일에 빈으로 등록한 컨트롤러다. "/form"이라는 URL로 들어오는 요청을 public String form() 메서드가 처리하도록 매핑하고 결과로 "hello" 라는 메시지를 반환한다.
from http://tonylim.tistory.com/276 by ccl(A) rewrite - 2021-12-10 16:27:17