问题
In my entities I have some hibernate annotations for validation, like @NotEmpty, @Pattern.. and others
In my controller, on save action, it has an @Valid parameter.
But if any entity has any required field, and there is no annotation I will have problems.
So I would like to test each entity, to ensure they have the necessary notes.
Something like:
@Test(expect=IllegalArgumentException.class)
public void testAllNull() {
Person p = new Persson(); // Person name has an @NotEmpty
validator.validate(p);
}
But how to validate it? Who is called to check @Valid?
Thanks.
回答1:
Here is a Spring v4.1.x based example of a test validating presence and processing of the @Valid annotation and building of custom JSON response in case of an error.
jUnit
import com.fasterxml.jackson.core.type.TypeReference;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import javax.inject.Inject;
import java.util.List;
import static org.abtechbit.miscboard.util.JsonUtils.toJson;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
RegistrationValidationTest.MockDependencies.class,
})
public class RegistrationValidationTest {
@Inject
MockMvc mvc;
@Test
public void validatesRegistration() throws Exception {
Registration registration = ... //build an invalid Registration object
MvcResult result = mvc.perform(post(RegistrationController.CONTEXT_REGISTER).
contentType(MediaType.APPLICATION_JSON).
content(toJson(registration))).
andExpect(status().isBadRequest()).
andExpect(content().contentType(MediaType.APPLICATION_JSON)).
andReturn();
assertThat(result.getResolvedException(), is(notNullValue()));
String content = result.getResponse().getContentAsString();
assertThat(content, is(notNullValue()));
List<Message> messages = JsonUtils.fromJson(content, new TypeReference<List<Message>>() {
});
assertThat(messages.size(), is(1));
}
public static class MockDependencies {
@Bean
public MockMvc mvc() {
return MockMvcBuilders.standaloneSetup(new RegistrationController()).build();
}
}
}
Controller
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;
@Controller
public class RegistrationController
{
public static final String CONTEXT_REGISTER = "/register";
@RequestMapping(value = CONTEXT_REGISTER, method = RequestMethod.POST)
@ResponseBody
public String register(@RequestBody @Valid Registration registration) {
//perform registration
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<List> handleValidationException(MethodArgumentNotValidException ex) {
//Build a list of custom Message{String message;} objects
List<Message> messages = ex.getBindingResult().getAllErrors().
stream().map(e->new Message(e.getDefaultMessage())).collect(Collectors.toList());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON).body(messages);
}
}
回答2:
I found out how to check:
@Autowired
private LocalValidatorFactoryBean validator;
...
validator.validateProperty(object, propertyName)
回答3:
Spring MVC Test Framework might be a good choice. By using this, you can be assured that validations in your tests runs codes as Spring @MVC actually works.
Actually, the @Valid
annotation is detected by HandlerMethodInvoker
, which processes annotations on the handler methods of Spring controllers. Internally, the actual validation logic is delegated to the Validator
bean depending on your application context settings. (Hibernate Validator is widely used.)
By default configuration (e.g. <mvc:annotation-driven />
), LocalValidatorFactoryBean
is used internally to process @Valid
annotation as @Falci noted, but it may differ time to time. Instead, Spring MVC Test Framework provides the same environment as the main application uses, hence a good choice.
来源:https://stackoverflow.com/questions/13745848/how-to-test-valid