【问题标题】:How to unit test a Spring MVC annotated controller?如何对 Spring MVC 注释控制器进行单元测试?
【发布时间】:2011-08-12 01:46:28
【问题描述】:

我正在关注 Spring 2.5 教程,同时尝试将代码/设置更新到 Spring 3.0。

Spring 2.5 我有 HelloController(供参考):

public class HelloController implements Controller {
    protected final Log logger = LogFactory.getLog(getClass());
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("Returning hello view");
        return new ModelAndView("hello.jsp");
    }
}

HelloController 的 JUnit 测试(供参考):

public class HelloControllerTests extends TestCase {
    public void testHandleRequestView() throws Exception{
        HelloController controller = new HelloController();
        ModelAndView modelAndView = controller.handleRequest(null, null);
        assertEquals("hello", modelAndView.getViewName());
    }
}

但现在我将控制器更新为 Spring 3.0,它现在使用注释(我还添加了一个 消息):

@Controller
public class HelloController {
    protected final Log logger = LogFactory.getLog(getClass());
    @RequestMapping("/hello")
    public ModelAndView handleRequest() {
        logger.info("Returning hello view");
        return new ModelAndView("hello", "message", "THIS IS A MESSAGE");
    }
}

知道我使用的是 JUnit 4.9,有人能解释一下如何对最后一个控制器进行单元测试吗?

【问题讨论】:

标签: java spring junit annotations


【解决方案1】:

基于注解的 Spring MVC 的一个优点是可以直接测试它们,如下所示:

import org.junit.Test;
import org.junit.Assert;
import org.springframework.web.servlet.ModelAndView;

public class HelloControllerTest {
   @Test
   public void testHelloController() {
       HelloController c= new HelloController();
       ModelAndView mav= c.handleRequest();
       Assert.assertEquals("hello", mav.getViewName());
       ...
   }
}

这种方法有什么问题吗?

对于更高级的集成测试,reference in Spring documentationorg.springframework.mock.web

【讨论】:

  • +1 非常感谢萨沙。它工作得很好。没想到这么简单。
  • 如果HelloController中有@Autowired组件,这将不起作用
  • @AramKocharyan:在单元测试中,我建议不要使用 Autowired 并通过构造函数或设置器显式提供依赖项。如果你真的想要所有春天的美好,你可能想看看static.springsource.org/spring/docs/3.0.x/…
  • @SashaO 是的,这周了解到:P 我只是用你所说的设置器设置自动装配的实例,效果很好。
  • 我觉得这种方法太白盒了。视图被称为“你好”的事实并不意味着正在做需要做的事情。我们正在使用 HttpClient 对我们的控制器进行单元测试。就像测试是浏览器一样。
【解决方案2】:

使用 mvc:annotation-driven 您必须有 2 个步骤:首先您使用 HandlerMapping 将请求解析到处理程序,然后您可以通过 HandlerAdapter 使用该处理程序执行该方法。比如:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("yourContext.xml")
public class ControllerTest {

    @Autowired
    private RequestMappingHandlerAdapter handlerAdapter;

    @Autowired
    private RequestMappingHandlerMapping handlerMapping;

    @Test
    public void testController() throws Exception {
        MockHttpServletRequest request = new MockHttpServletRequest();
        // request init here

        MockHttpServletResponse response = new MockHttpServletResponse();
        Object handler = handlerMapping.getHandler(request).getHandler();
        ModelAndView modelAndView = handlerAdapter.handle(request, response, handler);

        // modelAndView and/or response asserts here
    }
}

这适用于 Spring 3.1,但我想每个版本都必须存在一些变体。查看 Spring 3.0 代码,我会说 DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter 应该可以解决问题。

【讨论】:

  • @我在Object handler = handlerMapping.getHandler(request).getHandler(); 中遇到空指针异常我将如何解决
  • @jackyesind,正如答案中所建议的,必须初始化请求。类似new MockHttpServletResponse("GET", "/your/uri");
【解决方案3】:

您还可以查看其他独立于 Spring 的 Web 测试框架,例如 HtmlUnitSelenium。除了 Sasha 所描述的之外,您不会发现任何单独使用 JUnit 的更健壮的策略,除非您绝对应该断言该模型。

【讨论】:

    猜你喜欢
    • 2010-11-26
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 2012-05-25
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 2016-11-14
    相关资源
    最近更新 更多