我有一个叫浏览器POJO,我已经与Hibernate验证注解。
import org.hibernate.validator.constraints.NotEmpty;
public class Browser {
@NotEmpty
private String userAgent;
@NotEmpty
private String browserName;
...
}
我已经写了尝试验证我的控制方法捕获验证错误下面的单元测试。
@Test
public void testInvalidData() throws Exception {
Browser browser = new Browser("opera", null);
MockHttpServletRequest request = new MockHttpServletRequest();
BindingResult errors = new DataBinder(browser).getBindingResult();
// controller is initialized in @Before method
controller.add(browser, errors, request);
assertEquals(1, errors.getErrorCount());
}
这里是我的控制器的add()方法:
@RequestMapping(value = "/browser/create", method = RequestMethod.POST)
public String add(@Valid Browser browser, BindingResult result, HttpServletRequest request) throws Exception {
if (result.hasErrors()) {
request.setAttribute("errorMessage", result.getAllErrors());
return VIEW_NAME;
}
browserManager.save(browser);
request.getSession(false).setAttribute("successMessage",
String.format("Browser %s added successfully.", browser.getUserAgent()));
return "redirect:/" + VIEW_NAME;
}
我遇到的问题是,结果不会有错误,所以它就像是没有得到认可@Valid。 我尝试添加以下到我的测试类,但它并没有解决问题。
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"file:path-to/WEB-INF/spring-mvc-servlet.xml"})
有谁知道我怎么会得到@Valid得到认可(和验证)和JUnit测试时?
谢谢,
马特
该验证调用控制器之前完成的,所以你的测试不调用此验证。
还有另一种方法来测试控制器,在那里你不直接调用控制器。 相反,你构建和呼叫控制器被映射到URL。 这里是如何做到这一点的好例子: http://rstoyanchev.github.com/spring-31-and-mvc-test/#1
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=WebContextLoader.class, locations = {"classpath:/META-INF/spring/applicationContext.xml", "classpath:/META-INF/spring/applicationContext-test-override.xml", "file:src/main/webapp/WEB-INF/spring/webmvc-config.xml"})
public class MyControllerTest {
@Autowired
WebApplicationContext wac;
MockMvc mockMvc;
@Before
public void setup() {
this.mockMvc = MockMvcBuilders.webApplicationContextSetup(this.wac).build();
}
@Test
@Transactional
public void testMyController() throws Exception {
this.mockMvc.perform(get("/mycontroller/add?param=1").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(model().attribute("date_format", "M/d/yy h:mm a"))
.andExpect(model().attribute("myvalue", notNullValue()))
.andExpect(model().attribute("myvalue", hasSize(2)))
.andDo(print());
}
}
POM(需使用弹簧里程碑式回购):
<!-- required for spring-test-mvc -->
<repository>
<id>spring-maven-milestone</id>
<name>Spring Maven Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
</repository>
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test-mvc</artifactId>
<version>1.0.0.M1</version>
<scope>test</scope>
</dependency>
注:弹簧MVC测试的lib是不是生产准备好。 有在执行一定的差距。 我认为其计划春季3.2全面实施。
这种做法,因为它充分测试你的控制器一个伟大的想法。 它很容易弄乱你的控制器的映射,所以这些做真的需要进行单元测试。
验证器被称为超前的控制器方法被调用 - 结合的请求的方法的参数的过程中。 因为在这种情况下,在直接调用控制器的方法,所述结合和被绕过验证步骤。
得到的方式它的工作将是使呼叫通过Spring MVC栈控制器-有几个方法可以做到这一点,我觉得最好的方法是使用弹簧测试MVC提供了一个很好的机制,通过堆栈调用。
通过堆栈调用另一种方式是在的HandlerAdapter注入到测试是这样的:
@Autowired
private RequestMappingHandlerAdapter handlerAdapter;
然后在测试:
MockHttpServletRequest request = new MockHttpServletRequest("POST","/browser/create");
MockHttpServletResponse response = new MockHttpServletResponse();
httpRequest.addParameter(.... );//whatever is required to create Browser..
ModelAndView modelAndView = handlerAdapter.handle(httpRequest, response, handler);
基本上你实例化POJO与this.controller = new MyController()
调用其方法this.controller.add(...)
只需简单的Java有一个简单的对象,没有任何背景:@Valid不考虑。
@ContextConfiguration只会加载您可能豆类,以及可能的自定义验证等,但它不会做处理@Valid的魔力。
你需要的是一些模仿到控制器的请求add
方法。 完全效仿它,确认包括在内。 你是这样做的,因为你使用了一些弹簧试验设施不远处(实例化一个MockHttpServletRequest)。
如果你使用Spring 3.0.x的或更少 ,你需要做的
new AnnotationMethodHandlerAdapter()
.handle(request, new MockHttpServletResponse(), this.controller);
使它工作。
如果你使用Spring 3.1+,上述方案将无法正常工作( 见这个链接获取更多信息 )! 您将需要使用这个库 (由Spring团队,所以它的声音不要担心),而等待他们的下一个春天版本,它集成。 然后,你将不得不这样做
myMockController = MockMvcBuilders.standaloneSetup(new MyController()).build();
myMockController.perform(get("/browser/create")).andExpect(...);
也看看这些非常有趣的幻灯片 ,从罗森Stoyanchev(我们这里谈的部分开始在幻灯片#116)!
注:我不会在这种测试是否被视为单元测试和集成测试的争论进入。 有人会说这是相当我们在这里做集成测试,因为我们仿效的请求的完整路径。 但在另一方面,你仍然可以像@Mock的Mockito注释嘲笑你的控制器(或做任何其他嘲讽框架类似的东西),所以有些人会说,你可以在测试的范围缩小到几乎纯粹的“单元测试” 。 当然,你可以交替和纯粹的单元测试与普通的Java +嘲弄的框架控制器,但在这种情况下,这会不会让你测试@Valid验证。 做出你的选择 ! :)