I am trying to set up an integration testing with mockMvc, and i have a problem with it. Indeed, spring doesn't integrate any validation annotation.
For more precision, i put the code of the Controller class which could be tested :
@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;
}
}
Then, the object with contain both hibernate and javax annotation for validation :
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;
}
}
and the class which realizes the test:
@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());
}
}
When i launch the test, the error item doesn't exist, whereas login, password and mobile can't be validate by javax and hibernate annotation. Moreover, when i try to send an URL to localhost, validation worked and new user is not saved in database.
As you can see, i use a java code configuration for my web layer, i suppose the problem come from it. Moreover i download a project from the spring team in github (link : github.com/spring-projects/spring-mvc-showcase) which details all kind of test we can do with mockmvc. The validation one (in "org.springframework.samples.mvc.validation" package) doesn't work with my project configuration but very well with in it's original config.
To finish, i send you all my configuration classes
@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();
}
}
Thanks for your help.
Bookmark this question. Show activity on this post. To enable (unwrapped) method parameter validation in spring the controller has to be annotated with @Validated and the MethodValidationPostProcessor must be added to the context.
Spring also provides @Validator annotation and BindingResult class through which we can get the errors raised by Validator implementation in the controller request handler method.
I got same problem, after updating validator to 5.1.0.Final. Application is working perfectly but REST tests not (@Valid annotation is not considered at all). I resolved the problem with adding one additional dependency only for tests:
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
<scope>test</scope>
</dependency>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With