【问题标题】:How to test @Valid如何测试@Valid
【发布时间】:2012-12-06 14:36:06
【问题描述】:
在我的实体中,我有一些用于验证的休眠注释,例如 @NotEmpty、@Pattern.. 等
在我的控制器中,在保存操作时,它有一个 @Valid 参数。
但是如果任何实体有任何必填字段,并且没有注释我会遇到问题。
所以我想测试每个实体,以确保它们有必要的注释。
类似:
@Test(expect=IllegalArgumentException.class)
public void testAllNull() {
Person p = new Persson(); // Person name has an @NotEmpty
validator.validate(p);
}
但是如何验证呢?调用谁来检查@Valid?
谢谢。
【问题讨论】:
标签:
junit
annotations
hibernate-annotations
spring-annotations
【解决方案1】:
我发现了如何检查:
@Autowired
private LocalValidatorFactoryBean validator;
...
validator.validateProperty(object, propertyName)
【解决方案2】:
这是一个基于 Spring v4.1.x 的测试示例,用于验证 @Valid 注释的存在和处理以及在发生错误时构建自定义 JSON 响应。
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();
}
}
}
控制器
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);
}
}
【解决方案3】:
Spring MVC Test Framework 可能是一个不错的选择。通过使用它,您可以确保测试中的验证运行代码,因为 Spring @MVC 实际工作。
其实@Valid注解是被HandlerMethodInvoker检测到的,它处理Spring控制器的handler方法上的注解。在内部,实际的验证逻辑被委托给Validator bean,具体取决于您的应用程序上下文设置。 (Hibernate Validator 被广泛使用。)
在默认配置下(例如<mvc:annotation-driven />),LocalValidatorFactoryBean 在内部用于处理@Valid 注释,正如@Falci 所指出的那样,但有时可能会有所不同。相反,Spring MVC 测试框架提供了与主应用程序相同的环境,因此是一个不错的选择。