Search code examples
javavalidationspring-mvctestingspring-mvc-test

Spring setDisallowedFields is not working


The registration controller disallowes sending account id field by the following:

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setDisallowedFields("id");
    binder.setRequiredFields("username","password","emailAddress");
} 

@RequestMapping(method = { RequestMethod.POST, RequestMethod.PUT })
public String handleRegistration(@ModelAttribute Account account, BindingResult result) {
    if (result.hasErrors()) {
        return "customer/register";
    }

I Run the following test to make sure ID is not allowed:

@Test
public void testPutRequestWithIdPassedRegistrationController() throws Exception {
    this.mockMvc.perform(post("/customer/register")
            .param("id", "1")
            .param("username", "shouldBeIgnored")
            .param("password", "123")
            .param("emailAddress", "[email protected]")
            .param("address.country", "RU")
            .param("address.city", "Nsk")
            .param("address.street", "Lenin"))
            .andExpect(model().hasErrors())
            .andExpect(view().name("customer/register"));
}

But test fails cause: java.lang.AssertionError: Expected binding/validation errors

For comparation here is the test that tries to create account without passing not-nullable fields and it passes well, that means that setRequiredFields works fine:

@Test
public void testPutRequestWithoutNeededFieldsRegistrationController() throws Exception {
    this.mockMvc.perform(post("/customer/register"))
            .andDo(print())
            .andExpect(status().isOk())
            .andExpect(view().name("customer/register"))
            .andExpect(model().hasErrors())
            .andExpect(model().errorCount(3));
}

Why does it work by this way? How can I sure that id is not allowed?


Solution

  • Spring does not consider disallowed fields as errors. It just stores them as suppressedFields in the BindException. During debug I could access it via:

    ((BindingResult)getModelAndView(result).getModelMap().get("org.springframework.validation.BindingResult.account")).getSuppressedFields()
    

    When invoked from the hasErrors() method.

    So to make sure that id is not used, I just passed it via params and then checked that account with such name (it is a unique field) has another id value:

    String notExistingId = "999";
    String newUserName = "newUser";
    this.mockMvc.perform(post("/customer/register")
            .param("id", notExistingId)
            .param("username", newUserName)
            .param("password", "123")
            .param("emailAddress", "[email protected]")
            .param("address.country", "RU")
            .param("address.city", "Nsk")
            .param("address.street", "Lenin"))
            .andExpect(model().hasNoErrors())
            .andExpect(view().name("redirect:/index.htm"));
    Optional<Account> account = accountService.getAccount(newUserName);
    assertTrue( "Account with the username should exist", account.isPresent());
    assertNotSame("Account id should not be equal to the id we try to pass with parameters",
            Long.parseLong(notExistingId),
            account.get().getId());