I am unit testing a Spring controllers post method (using org.springframework.test.web.servlet.MockMvc
), and I'm trying to confirm that when there are validation errors in the form it will send the view back to the form by checking the BindingResult.hasErrors
method.
Here is my test
@Test
public void testFilterChannelProgrammesWhenChannelListAndGenreListAreEmptyAndProgNameIsTooLong() throws Exception {
String progName = TestUtil.createStringWithLength(301);
mockMvc.perform(post("/api/filter")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("progName", progName)
.sessionAttr("filter", new ProgrammeSearchDTO())
)
.andExpect(status().isOk())
.andExpect(view().name("api/filter"))
.andExpect(forwardedUrl("/WEB-INF/jsp/api/filter.jsp"))
.andExpect(model().attributeHasFieldErrors("filter", "progName"))
.andExpect(model().attributeHasFieldErrors("filter", "genreIdList"))
.andExpect(model().attributeHasFieldErrors("filter", "channelIdList"))
.andExpect(model().attribute("filter", hasProperty("progName", is(progName))));
verifyZeroInteractions(channelProgrammeServiceMock);
}
Here is the DTO that the session attribute is bound to
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
public class ProgrammeSearchDTO {
@NotEmpty
private String[] channelIdList;
@NotEmpty
private String[] genreIdList;
private String fromDateTime;
private String toDateTime;
@Length(max = 200)
private String progName;
private boolean subtitled;
private boolean signed;
private boolean film;
public String[] getChannelIdList() {
return channelIdList;
}
public String getFromDateTime() {
return fromDateTime;
}
public String[] getGenreIdList() {
return genreIdList;
}
public String getProgName() {
return progName;
}
public String getToDateTime() {
return toDateTime;
}
public boolean isFilm() {
return film;
}
public boolean isSigned() {
return signed;
}
public boolean isSubtitled() {
return subtitled;
}
public void setChannelIdList(String[] channelIdList) {
this.channelIdList = channelIdList;
}
public void setFilm(boolean film) {
this.film = film;
}
public void setFromDateTime(String fromDateTime) {
this.fromDateTime = fromDateTime;
}
public void setGenreIdList(String[] genreIdList) {
this.genreIdList = genreIdList;
}
public void setProgName(String progName) {
this.progName = progName;
}
public void setSigned(boolean signed) {
this.signed = signed;
}
public void setSubtitled(boolean subtitled) {
this.subtitled = subtitled;
}
public void setToDateTime(String toDateTime) {
this.toDateTime = toDateTime;
}
}
And the controller method
@RequestMapping(value = "/api/filter", method = RequestMethod.POST)
public String filterChannelProgrammes(@Valid @ModelAttribute ProgrammeSearchDTO programmeSearchDTO, BindingResult result, Model model) {
if(result.hasErrors()) {
return "api/filter";
}
model.addAttribute("results", null);
return "redirect:filterResults";
}
For this test the return "api/filter";
should be actioned, but hasErrors()
is always false. I have also tried with the following
@RequestMapping(value = "/api/filter", method = RequestMethod.POST)
public String filterChannelProgrammes(@Valid @ModelAttribute("filter") ProgrammeSearchDTO programmeSearchDTO, BindingResult result, Model model) {
if(result.hasErrors()) {
return "api/filter";
}
model.addAttribute("results", null);
return "redirect:filterResults";
}
But hasErrors()
is still false
EDIT
After some more digging I have this sorted, it also required the following in the context config xml
<mvc:annotation-driven />
<bean id="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
And these dependencies in the maven pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.2.Final</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
After some more digging I have this sorted, it also required the following in the context config xml
And these dependencies in the maven pom.xml