programing

@PathVariable을 사용하여 Spring MVC 컨트롤러를 단위 테스트하는 방법은 무엇입니까?

muds 2023. 10. 13. 22:35
반응형

@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() 메서드에서 예외가 발생한다는 것입니다.

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)

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
    }
}

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

봄 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/ 을 참조하십시오.

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

예외 메시지는 샘플 코드에 없는 "피드" 변수를 나타냅니다. 이 변수는 사용자가 보여주지 않은 것에 의해 발생한 것일 가능성이 높습니다.

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

Spring이 작동한다고 가정하고 자신의 클래스를 테스트하는 것이 좋습니다. 예를 들어, 콜을 테스트하는 것이 좋습니다.MyController.doSomething()직접적으로.이것이 주석 접근 방식의 장점 중 하나입니다. 즉, 모의 요청 및 응답을 사용할 필요가 없고 도메인 POJO만 사용하면 됩니다.

요청 개체에 수동으로 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
}

저는 분명히 더 좋은 선택지를 찾고 싶습니다.

Spring 3.0.x를 사용하는 경우.

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

마이컨트롤러매개 변수.java 사용

@Controller
public class MyControllerWithParameter {
@RequestMapping("/testUrl/{pathVar}/some.html")
public String passOnePathVar(@PathVariable String pathVar, ModelMap model){
    model.addAttribute("SomeModelAttribute",pathVar);
    return "viewName";
}
}

MyControllerTest.java

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

}

제 원래 답변이 @PathVariable에 도움이 될지 잘 모르겠습니다.@PathVariable을 테스트하려고 했는데 다음과 같은 예외가 발생합니다.

조직, 스프링 프레임워크, 웹, bind, annot.지지하다.핸들러 메소드호출예외:핸들러 메서드 [public org.springframework]를 호출하지 못했습니다.웹.서블릿Model AndView 테스트.마이클래스yMethod(검정).SomeType)]. 중첩 예외는 java.lang입니다.잘못된 상태 예외:@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 주석에 대한 새로운 블로그 게시물을 추가했습니다.

언급URL : https://stackoverflow.com/questions/1401128/how-to-unit-test-a-spring-mvc-controller-using-pathvariable

반응형