복붙노트

[SPRING] @PathVariable을 사용하여 Spring MVC 컨트롤러를 단위 테스트하는 방법?

SPRING

@PathVariable을 사용하여 Spring MVC 컨트롤러를 단위 테스트하는 방법?

나는 이것과 비슷한 간단한 주석 처리 된 컨트롤러를 가지고있다 :

@Controller
public class MyController {
  @RequestMapping("/{id}.html")
  public String doSomething(@PathVariable String id, Model model) {
    // do something
    return "view";
  }
}

다음과 같은 단위 테스트로 테스트하고 싶습니다.

public class MyControllerTest {
  @Test
  public void test() {
    MockHttpServletRequest request = new MockHttpServletRequest();
    request.setRequestURI("/test.html");
    new AnnotationMethodHandlerAdapter()
      .handle(request, new MockHttpServletResponse(), new MyController());
    // assert something
  }
}

문제는 AnnotationMethodHandlerAdapter.handler () 메서드가 예외를 throw합니다.

java.lang.IllegalStateException: Could not find @PathVariable [id] in @RequestMapping
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter$ServletHandlerMethodInvoker.resolvePathVariable(AnnotationMethodHandlerAdapter.java:642)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:514)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:262)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:146)

해결법

  1. ==============================

    1.Spring 3.2에서, 이것을 우아하고 쉬운 방법으로 테스트 할 수있는 적절한 방법이있다. 다음과 같은 일을 할 수 있습니다.

    Spring 3.2에서, 이것을 우아하고 쉬운 방법으로 테스트 할 수있는 적절한 방법이있다. 다음과 같은 일을 할 수 있습니다.

    @RunWith(SpringJUnit4ClassRunner.class)
    @WebAppConfiguration
    @ContextConfiguration("servlet-context.xml")
    public class SampleTests {
    
      @Autowired
      private WebApplicationContext wac;
    
      private MockMvc mockMvc;
    
      @Before
      public void setup() {
        this.mockMvc = webAppContextSetup(this.wac).build();
      }
    
      @Test
      public void getFoo() throws Exception {
        this.mockMvc.perform(get("/foo").accept("application/json"))
            .andExpect(status().isOk())
            .andExpect(content().mimeType("application/json"))
            .andExpect(jsonPath("$.name").value("Lee"));
      }
    }
    

    자세한 내용은 http://blog.springsource.org/2012/11/12/spring-framework-3-2-rc1-spring-mvc-test-framework/에서 확인하십시오.

  2. ==============================

    2.나는 Spring 레퍼런스 매뉴얼의 용어를 기반으로 통합 테스트를 한 후에 자신이하는 것을 호출 할 것이다. 방법에 대해 같은 일을 :

    나는 Spring 레퍼런스 매뉴얼의 용어를 기반으로 통합 테스트를 한 후에 자신이하는 것을 호출 할 것이다. 방법에 대해 같은 일을 :

    import static org.springframework.test.web.ModelAndViewAssert.*;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({/* include live config here
        e.g. "file:web/WEB-INF/application-context.xml",
        "file:web/WEB-INF/dispatcher-servlet.xml" */})
    public class MyControllerIntegrationTest {
    
        @Inject
        private ApplicationContext applicationContext;
    
        private MockHttpServletRequest request;
        private MockHttpServletResponse response;
        private HandlerAdapter handlerAdapter;
        private MyController controller;
    
        @Before
        public void setUp() {
           request = new MockHttpServletRequest();
           response = new MockHttpServletResponse();
           handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
           // I could get the controller from the context here
           controller = new MyController();
        }
    
        @Test
        public void testDoSomething() throws Exception {
           request.setRequestURI("/test.html");
           final ModelAndView mav = handlerAdapter.handle(request, response, 
               controller);
           assertViewName(mav, "view");
           // assert something
        }
    }
    

    자세한 내용은 스프링 MVC 주석 통합 테스트에 대한 블로그 항목을 작성했습니다.

  3. ==============================

    3.Spring MVC 테스트를위한 유망한 프레임 워크 https://github.com/SpringSource/spring-test-mvc

    Spring MVC 테스트를위한 유망한 프레임 워크 https://github.com/SpringSource/spring-test-mvc

  4. ==============================

    4.예외 메시지는 샘플 코드에없는 "피드"변수를 나타내며, 사용자가 표시하지 않은 것으로 인해 발생했을 수 있습니다.

    예외 메시지는 샘플 코드에없는 "피드"변수를 나타내며, 사용자가 표시하지 않은 것으로 인해 발생했을 수 있습니다.

    또한, 당신의 테스트는 Spring과 당신의 코드를 테스트하는 것입니다. 이게 정말로 당신이하고 싶은 일입니까?

    Spring이 작동한다고 가정하는 것이 낫다. MyController.doSomething ()을 직접 호출한다. 이것이 주석 접근법의 한 가지 이점입니다. 모의 요청과 응답을 사용할 필요가 없으며 도메인 POJO 만 사용하면됩니다.

  5. ==============================

    5.여기 스프링 테스트 -mvc가 아닌 스프링 테스트를 사용하여 Emil과 scarba05의 합병을 제안합니다. 이 답변을 건너 뛰고 Spring 3.2.x 이상을 사용하는 경우 spring-test-mvc 예제를 참조하십시오.

    여기 스프링 테스트 -mvc가 아닌 스프링 테스트를 사용하여 Emil과 scarba05의 합병을 제안합니다. 이 답변을 건너 뛰고 Spring 3.2.x 이상을 사용하는 경우 spring-test-mvc 예제를 참조하십시오.

    @Controller
    public class MyControllerWithParameter {
    @RequestMapping("/testUrl/{pathVar}/some.html")
    public String passOnePathVar(@PathVariable String pathVar, ModelMap model){
        model.addAttribute("SomeModelAttribute",pathVar);
        return "viewName";
    }
    }
    
    import static org.springframework.test.web.ModelAndViewAssert.assertViewName;
    import java.util.HashMap;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.mock.web.MockHttpServletRequest;
    import org.springframework.mock.web.MockHttpServletResponse;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    import org.springframework.test.web.ModelAndViewAssert;
    import org.springframework.web.servlet.HandlerAdapter;
    import org.springframework.web.servlet.HandlerMapping;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = 
        {"file:src\\main\\webapp\\WEB-INF\\spring\\services\\servlet-context.xml" 
        })
    public class MyControllerTest {
    
    private MockHttpServletRequest request;
    private MockHttpServletResponse response;
    private HandlerAdapter handlerAdapter;
    
    @Before
    public void setUp() throws Exception {
        request = new MockHttpServletRequest();
        response = new MockHttpServletResponse();
        this.handlerAdapter = applicationContext.getBean(AnnotationMethodHandlerAdapter.class);
    }
    
    //  Container beans
    private MyControllerWithParameter myController;
    private ApplicationContext applicationContext;
    public ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    public MyControllerWithParameter getMyController() {
        return myController;
    }
    @Autowired
    public void setMyController(MyControllerWithParameter myController) {
        this.myController = myController;
    }
    
    @Test
    public void test() throws Exception {
        request.setRequestURI("/testUrl/Irrelavant_Value/some.html");
        HashMap<String, String> pathvars = new HashMap<String, String>();
        // Populate the pathVariable-value pair in a local map
        pathvars.put("pathVar", "Path_Var_Value");
        // Assign the local map to the request attribute concerned with the handler mapping 
        request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, pathvars);
    
        final ModelAndView modelAndView = this.handlerAdapter.handle(request, response, myController);
    
        ModelAndViewAssert.assertAndReturnModelAttributeOfType(modelAndView, "SomeModelAttribute", String.class);
        ModelAndViewAssert.assertModelAttributeValue(modelAndView, "SomeModelAttribute", "Path_Var_Value");
        ModelAndViewAssert.assertViewName(modelAndView, "viewName");
    }
    

    }

  6. ==============================

    6.PathVariable 매핑을 요청 개체에 수동으로 삽입 할 수 있음을 발견했습니다. 이것은 분명히 이상적이지는 않지만 작동하는 것처럼 보입니다. 귀하의 예를 들면 다음과 같습니다 :

    PathVariable 매핑을 요청 개체에 수동으로 삽입 할 수 있음을 발견했습니다. 이것은 분명히 이상적이지는 않지만 작동하는 것처럼 보입니다. 귀하의 예를 들면 다음과 같습니다 :

    @Test
    public void test() {
        MockHttpServletRequest request = new MockHttpServletRequest();
        request.setRequestURI("/test.html");
        HashMap<String, String> pathvars = new HashMap<String, String>();
        pathvars.put("id", "test");
        request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, pathvars);
        new AnnotationMethodHandlerAdapter().handle(request, new MockHttpServletResponse(), new MyController());
       // assert something
    }
    

    확실히 더 나은 옵션을 찾는 데 관심이 있습니다.

  7. ==============================

    7.원래의 대답이 @PathVariable에 도움이 될지 잘 모르겠습니다. 방금 @PathVariable 테스트를 시도하고 다음 예외가 발생합니다.

    원래의 대답이 @PathVariable에 도움이 될지 잘 모르겠습니다. 방금 @PathVariable 테스트를 시도하고 다음 예외가 발생합니다.

    org.springframework.web.bind.annotation.support.HandlerMethodInvocationException : 핸들러 메소드를 호출하지 못했습니다 [public org.springframework.web.servlet.ModelAndView test.MyClass.myMethod (test.SomeType)]; 중첩 예외는 java.lang.IllegalStateException입니다 : @RequestMapping에서 @PathVariable [parameterName]을 찾을 수 없습니다.

    그 이유는 요청의 경로 변수가 인터셉터에 의해 파싱되기 때문입니다. 다음 접근 방식은 나를 위해 작동합니다.

    import static org.springframework.test.web.ModelAndViewAssert.*;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration({"file:web/WEB-INF/application-context.xml",
            "file:web/WEB-INF/dispatcher-servlet.xml"})    
    public class MyControllerIntegrationTest {
    
        @Inject
        private ApplicationContext applicationContext;
    
        private MockHttpServletRequest request;
        private MockHttpServletResponse response;
        private HandlerAdapter handlerAdapter;
    
        @Before
        public void setUp() throws Exception {
            this.request = new MockHttpServletRequest();
            this.response = new MockHttpServletResponse();
    
            this.handlerAdapter = applicationContext.getBean(HandlerAdapter.class);
        }
    
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            final HandlerMapping handlerMapping = applicationContext.getBean(HandlerMapping.class);
            final HandlerExecutionChain handler = handlerMapping.getHandler(request);
            assertNotNull("No handler found for request, check you request mapping", handler);
    
            final Object controller = handler.getHandler();
            // if you want to override any injected attributes do it here
    
            final HandlerInterceptor[] interceptors =
                handlerMapping.getHandler(request).getInterceptors();
            for (HandlerInterceptor interceptor : interceptors) {
                final boolean carryOn = interceptor.preHandle(request, response, controller);
                if (!carryOn) {
                    return null;
                }
            }
    
            final ModelAndView mav = handlerAdapter.handle(request, response, controller);
            return mav;
        }
    
        @Test
        public void testDoSomething() throws Exception {
            request.setRequestURI("/test.html");
            request.setMethod("GET");
            final ModelAndView mav = handle(request, response);
            assertViewName(mav, "view");
            // assert something else
        }
    

    통합 테스트에 대한 새로운 블로그 게시물을 추가했습니다. mvc annotations

  8. from https://stackoverflow.com/questions/1401128/how-to-unit-test-a-spring-mvc-controller-using-pathvariable by cc-by-sa and MIT license