fall
fall

Reputation: 1202

Test @Valid annotation with SpringMVC Maven

I am working on the chapter 5 example of the book Spring in Action 4. When I am running the Test classes I found one of the @Valid test is not working, it appears as if the validation never occured(returned status code of 302 and view's name is "/spitter/null"). However, it works fine when I run it in Tomcat.

The validatioon jars(hibernate-validator and its dependencies) are loaded with Maven.

The whole project is on github.

Any ideas?

test code snippet:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes={RootConfig.class, WebConfig.class})
public class SpitterControllerTest {
    @Test
    public void shouldFailValidationWithNoData() throws Exception {
        SpitterRepository mockRepository = mock(SpitterRepository.class);    
        SpitterController controller = new SpitterController(mockRepository);
        MockMvc mockMvc = standaloneSetup(controller).build();

        mockMvc.perform(post("/spitter/register"))
            .andExpect(status().isOk())
            .andExpect(view().name("registerForm"))
            .andExpect(model().errorCount(5))
            .andExpect(model().attributeHasFieldErrors(
                "spitter", "firstName", "lastName", "username", "password", "email"));
    }
}

SpitterController snippet:

  @RequestMapping(value="/register", method=POST)
  public String processRegistration(
      @Valid Spitter spitter, 
      Errors errors) {
    if (errors.hasErrors()) {
      return "registerForm";
    }

    spitterRepository.save(spitter);
    return "redirect:/spitter/" + spitter.getUsername();
  }

Spitter snippet:

@NotNull
  @Size(min=5, max=16)
  private String username;

  @NotNull
  @Size(min=5, max=25)
  private String password;

  @NotNull
  @Size(min=2, max=30)
  private String firstName;

  @NotNull
  @Size(min=2, max=30)
  private String lastName;

  @NotNull
  @Email
  private String email;

Thanks a lot!

Upvotes: 1

Views: 1416

Answers (3)

fall
fall

Reputation: 1202

I tried this post's best answer and it worked. I changed the hibernate-validator version from 5.4.1.final to 5.2.4.final in pom. The github project is updated as well.

Upvotes: 1

Sean Carroll
Sean Carroll

Reputation: 2711

I cloned your repository and was able to get the valiation working by updating your jsp-api dependency to 2.2

<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.2</version>
    <scope>provided</scope>
</dependency>

There are newer versions of that dependency that you might want to take a look at. When using the 2.1 version there were no validators being registered/added to ExtendedServletRequestDataBinder or more precisely the SpringValidatorAdapter targetValidator was null.

The root cause was that the exception below was being thrown in OptionalValidatorFactoryBean.afterPropertiesSet

javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead

I noticed that you updated your shouldFailValidationWithNoData test to use webAppContextSetup but still have a call to mock(SpitterRepository.class) which isn't necessary.

Upvotes: 1

Arpit Aggarwal
Arpit Aggarwal

Reputation: 29316

Mark your SpitterController with @Validated

import org.springframework.validation.annotation.Validated;

@Controller
@Validated
@RequestMapping("/spitter")
public class SpitterController {

@Autowired the SpitterController and create MethodValidationPostProcessor bean which delegates to a JSR-303 provider for performing method-level validation on annotated methods, as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { RootConfig.class, WebConfig.class,
        SpitterControllerTest.Config.class })
public class SpitterControllerTest {

    @Autowired
    private SpitterController spitterController;

    @Configuration
    public static class Config {
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            return new MethodValidationPostProcessor();
        }
    }

    @Test
    public void shouldFailValidationWithNoData() throws Exception {
    }

}

Upvotes: 0

Related Questions