我正在使用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帮助我看到了我想在测试中检查的对象是BindingResult
或Errors
对象。但是,它不是我编写的任何方法的返回值的一部分。
我想我可以尝试为控制器和模板之间的ViewResolver
或任何自动生成的对象中间对象编写测试,或者可以屠宰控制器类以允许我的测试类访问错误。两者似乎都是坏主意。当前的解决方案是考虑该场景需要进行过多的测试,但是我不希望这在原则上是无法测试的。
答案 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