如何为包含错误/ BindingResult的控制器编写测试?

时间:2019-04-05 12:49:05

标签: java spring-mvc junit thymeleaf

我正在使用Spring Boot和Spring MVC在一个简单的网站上工作,但遇到了无法编写测试的情况。您如何测试Controller如何处理Errors,这会影响用户界面,但不包含在ModelAndView中?

我在以HTML格式显示错误消息时遇到了麻烦,经过无奈之后,我发现这是因为我在将ModelAndView中的Form对象作为对象返回之前将其覆盖了。

这是有问题的代码

@PostMapping
ModelAndView processPost(@Valid IdAndAmountForm idAndAmountForm, Errors errors) {
    if (errors.hasErrors()) {
        var beer = service.findBeerById(idAndAmountForm.getId());
        return new ModelAndView("beerView")
                .addObject("beer", beer)
                .addObject("idAndAmountForm", idAndAmountForm);
    } else {
        cart.add(idAndAmountForm);
        return new ModelAndView("redirect:/cart");
    }
}

它可以正常工作/工作,行为正常,在删除HTML验证后,在span中填充相应的消息。

    <form th:action="@{/beer}" th:object="${idAndAmountForm}" method="post">
        <label>
            Amount
            <span th:errors="*{amount}"></span>
            <input th:field="*{amount}" type="number" min="1" required>
        </label>

我的错误是控制器的第7行,我之前有.addObject("idAndAmountForm", new IdAndAmountForm()); 没有与新表单相关的错误,因此没有错误消息显示。或那是我认为发生的事情。

现在如何编写检测到此错误行为的测试? 我花了一些时间剖析Model,寻找我知道以某种方式传递给Thymeleaf模板的错误消息,然后断定这些错误消息是由Spring分别处理的。 This answer帮助我看到了我想在测试中检查的对象是BindingResultErrors对象。但是,它不是我编写的任何方法的返回值的一部分。

我想我可以尝试为控制器和模板之间的ViewResolver或任何自动生成的对象中间对象编写测试,或者可以屠宰控制器类以允许我的测试类访问错误。两者似乎都是坏主意。当前的解决方案是考虑该场景需要进行过多的测试,但是我不希望这在原则上是无法测试的。

1 个答案:

答案 0 :(得分:0)

您可以使用Spring编写Controller测试来实现所需的功能。 Spring MVC测试框架提供了一个非常好用且易于阅读的流畅API,可用于使用 MockMvc 在MVC中测试各种场景。

对于您的用例,测试模型属性绑定结果错误,您可能会编写一个使用 MockMvcResultMatchers 和静态 status()的测试model() view() flash()

抽出时间探索这些内容,看看可以调用哪些方法。 例如,在模型中,您具有与fieldErrors相关的多种方法,通过检查您可以达到所需的精确度。 最后,您的测试课程将如下所示:

mockMvc.perform(post(YOUR_URL).contentType(APPLICATION_FORM_URLENCODED)
    .param(...)
    .param(...)
    .andExpect(model().hasErrors())
    .andExpect(model().attributeHasFieldErrors(FORM_MODEL_NAME, "field"))
    .andExpect(model().attributeHasFieldErrorCode(FORM_MODEL_NAME, "anotherfield", "error")
    .andExpect(view().name(YOUR_VIEW));

更多有关Spring MVC测试框架的信息: https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-mvc-test-framework