Spring mockMvc在我的测试中不考虑验证

时间:2014-06-04 23:53:43

标签: java spring validation spring-mvc

我正在尝试使用mockMvc设置集成测试,我遇到了问题。实际上,spring并没有集成任何验证注释。
为了更加精确,我把Controller类的代码放到了可以测试的地方:

@Controller
public class UserRegisterController {
    private final Log log = LogFactory.getLog(UserRegisterController.class);

    private UserManager userManager;

    @Autowired
    public UserRegisterController(UserManager userManager){
        this.userManager = userManager;
    }

    /**
     * Register a new user.
     *
     */
    @RequestMapping(value = "/User/Register", 
            method = RequestMethod.GET
    )
    public @ResponseBody SimpleMessage submitForm(
            @Valid UserInfoNew userInfo,
            BindingResult result
    ){
        if(log.isInfoEnabled())
            log.info("Execute UserRegister action");
        SimpleMessage message;

        try {
            if(result.hasErrors()){
                if(log.isFatalEnabled())
                    log.fatal("Parameters sent by user for registering aren't conform. Errors are : "
                            + result.getFieldErrors().toString());
                throw new Exception(result.getFieldErrors().toString());
            }

            User user = new User();
            user.setLogin(userInfo.getLogin());
            user.setFamilyName(userInfo.getFamilyName());
            user.setFirstName(userInfo.getFirstName());
            user.setPassword(userInfo.getPassword());
            user.setDateBirthday(userInfo.getDateBirthday());
            user.setEmail(userInfo.getEmail());
            user.setMobile(userInfo.getMobile());
            user.setAddress(userInfo.getAddress());

            userManager.createUser(user);

            User newUser = userManager.findLastUserCreated();

            //Change to null some sensitive or useless return parameters
            newUser.setPassword(null);
            //

            message = new SimpleMessage(null, newUser);
        } catch (Exception e) {
            if(log.isErrorEnabled())
                log.error("A problem of type : " + e.getClass() 
                        + " has occured, with message : " + e.getMessage());
            message = new SimpleMessage(
                            new SimpleException(e.getClass(), e.getMessage()), null);
        }

        return message;
    }
}

然后,包含hibernate和javax注释的对象进行验证:

public abstract class UserParameters {

    @Min(1)
    protected Long id;

    @Length(min=4, max=20)
    protected String login;

    @Length(min=4, max=20)
    protected String familyName;

    @Length(min=4, max=20)
    protected String firstName;

    @Pattern(regexp="^.*(?=.{8,20})(?=.*[a-z]+)(?=.*[a-z]+)(?=.*[A-Z]+)(?=.*[A-Z]+)"
            + "(?=.*[0-9]+)(?=.*[0-9]+)(?=.*[@$%*#]+).*$")
    protected String password;

    @Past
    protected Calendar dateBirthday;

    @Email
    @Length(max=255)
    protected String email;

    @Pattern(regexp="^[0]{1}[67]{1}[ .-]{1}[0-9]{2}[ .-]{1}"
            + "[0-9]{2}[ .-]{1}[0-9]{2}[ .-]{1}[0-9]{2}$")
    protected String mobile;

    @Length(max=255)
    protected String address;

    protected Calendar dateCreation;

    protected Calendar dateLastAccess;
}

public class UserInfoNew extends UserParameters  implements Serializable{   

    private static final long serialVersionUID = 4427131414801253777L;

    @NotBlank
    public String getLogin() {
            return login;
    }   
    public void setLogin(String Login) {
            this.login = Login;
    }

    public String getFamilyName() {
            return familyName;
    }   
    public void setFamilyName(String Name) {
            this.familyName = Name;
    }

    public String getFirstName() {
            return firstName;
    }   
    public void setFirstName(String FirstName) {
            this.firstName = FirstName;
    }

    @NotBlank
    public String getPassword() {
            return password;
    }   
    public void setPassword(String Password){
        this.password = Password;
    }

    public Calendar getDateBirthday() {
        return dateBirthday;
    }
    public void setDateBirthday(Calendar strBirthDay) {     
        this.dateBirthday = strBirthDay;
    }

    public String getEmail() {
        return email;
    }
    public void setEmail(String Mail) {
        this.email = Mail;
    }

    @NotBlank
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String Mobile) {
        this.mobile = Mobile;
    }

    public String getAddress() {
        return address;
    }   
    public void setAddress(String Address) {
        this.address = Address;
    }
}

以及实现测试的类:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {
        WebInit_Test.class,
        AppConfig_Test.class,
        WebConfig_1.class,
        WebConfig_2.class,
        WebSocketConfig.class
})
public class UserControllersTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @Before
    public void setUp() throws Exception {

        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
                        .alwaysExpect(status().isOk())
                           .alwaysExpect(content().contentType("application/json;charset=UTF-8"))
                    .build();
}

@Test
public void userRegister() throws Exception {
    //doesn't consider @Valid during test
    mockMvc.perform(get("/User/Register?Login=A&Password=aaAA&Mobile=0134320285")
            .contentType(MediaType.ALL)
    )
            .andExpect(jsonPath("error").exists());


}
}

当我启动测试时,错误项目不存在,而登录,密码和移动设备无法通过javax和hibernate注释进行验证。此外,当我尝试将URL发送到localhost时,验证工作,新用户不保存在数据库中。
正如你所看到的,我为我的web层使用了java代码配置,我想这个问题来自于它。此外,我从github的spring团队下载了一个项目(链接:github.com/spring-projects/spring-mvc-showcase),详细介绍了我们可以用mockmvc做的所有测试。验证一个(在“org.springframework.samples.mvc.validation”包中)不适用于我的项目配置,但在其原始配置中非常好。

为了完成,我发送了所有配置类

@Configuration
public class WebInit_Test extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[] { AppConfig_Test.class };
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] { WebConfig_1.class, WebConfig_2.class, WebSocketConfig.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

    @Override
    protected void customizeRegistration(Dynamic registration) {
        registration.setInitParameter("dispatchOptionsRequest", "true");
        registration.setLoadOnStartup(1);
    }
}

@Configuration
@ImportResource({
    "classpath:/applicationContext-dao.xml",
    "classpath:/applicationContext-datasource-test.xml",
    "classpath:/applicationContext-service.xml"
})
public class AppConfig_Test {

}

@Configuration
@EnableWebMvc
@ComponentScan(
        basePackages = "project.web",
        excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, value = Configuration.class)
)
public class WebConfig_1 extends WebMvcConfigurationSupport {

    @Autowired
    private FormattingConversionServiceFactoryBean conversionService;

    @Bean
    @Override
    public FormattingConversionService mvcConversionService() {
        FormattingConversionService conversionService = this.conversionService.getObject();
        addFormatters(conversionService);
        return conversionService;
    }
}

@Configuration
public class WebConfig_2 extends WebMvcConfigurerAdapter{

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
    }

    /**
     * Configure output mapping, see 
     * {@link http://stackoverflow.com/questions/4823358/spring-configure-responsebody-json-format} 
     * for more information
     * 
     * @param converters
     *          a list of {@link HttpMessageConverter<?>}
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        final ObjectMapper objectMapper = new ObjectMapper();        
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        converter.setObjectMapper(objectMapper);
        converters.add(converter);
        super.configureMessageConverters(converters);
    }
}

@Configuration
//@EnableScheduling
@ComponentScan(
        basePackages="project.web",
        excludeFilters = @ComponentScan.Filter(type= FilterType.ANNOTATION, value = Configuration.class)
)
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/friendship", "/message", "/journey", "/information");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/client").withSockJS();
    }
}

感谢您的帮助。

3 个答案:

答案 0 :(得分:9)

在将验证器更新到5.1.0.Final之后,我遇到了同样的问题。应用程序工作正常但REST测试没有(@Valid注释根本没有考虑)。我通过仅为测试添加一个附加依赖项来解决问题:

   <dependency>
     <groupId>javax.el</groupId>
     <artifactId>javax.el-api</artifactId>
     <version>2.2.4</version>
     <scope>test</scope>
  </dependency>

答案 1 :(得分:5)

如果您使用的是hibernate版本5.4.1.Final,只需在测试中添加以下依赖项

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.el</artifactId>
    <version>3.0.0</version>
</dependency>

此依赖关系是“提供”依赖关系。你可以在maven站点找到你的hibernate版本的匹配依赖项。 https://mvnrepository.com/artifact/org.hibernate/hibernate-validator/5.4.1.Final

例如,如果您使用的是5.4.1版本,请转到上面的链接并检查提供的依赖项并使用它。

答案 2 :(得分:3)

好的,我刚刚发现了由mockmvc不考虑验证的原因。它在我的pom中只是一个坏依赖:  

我用过

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>5.1.0.Final</version>
</dependency>

当我用

替换它时
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.0.0.GA</version>
</dependency>
<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>4.1.0.Final</version>
</dependency>
测试工作就好了!

问题解决了,但我想知道为什么问题来自这一部分。 hibernate-validator 5.1.0.Final包括传递依赖中的javax验证,所以通常情况下,这个问题永远不会出现。