我正在构建一个Spring Boot 1.4.1, Spring Data Jpa和Spring Data Test的应用程序。
我有以下控制器,我想用它返回分页帐户:
@RequestMapping(method=RequestMethod.GET)
public HttpEntity<PagedResources<Account>> getAccounts(
Pageable pageable,
PagedResourcesAssembler assembler,
@RequestParam(value="name", required = false) String name,
@RequestParam(value="username", required = false) String username,
@RequestParam(value="email", required = false) String email,
@RequestParam(value="lastName", required = false) String lastName,
@RequestParam(value="size", required = true, defaultValue = "10") Integer size,
@RequestParam(value="page", required = true, defaultValue = "0") int page,
@RequestParam(value="sort", required = false, defaultValue = "username") String sort,
@RequestParam(value="direction", required = false, defaultValue = "asc") String direction,
UriComponentsBuilder uriBuilder,
HttpServletRequest request,
HttpServletResponse response) {
// form page request
AccountList list = null;
Page<Account> resultPage = null;
Direction sortDirection = Direction.ASC;
if(direction.equals("desc")) {
sortDirection = Direction.DESC;
}
PageRequest pReq = new PageRequest(page, size, sortDirection, sort);
resultPage = accountService.findAll(pReq);
return new ResponseEntity<>(assembler.toResource(resultPage), HttpStatus.OK);
}
我的测试方法是:
@Test
public void getAccountsTest() throws Exception {
String uri = uriBase + "/accounts";
List<Account> list = new ArrayList<Account>();
list.add(accountOne);
list.add(accountTwo);
Page<Account> returnPage = new PageImpl<Account>(list, new PageRequest(0,10), list.size());
when(accountService.findAll(any(PageRequest.class))).thenReturn(returnPage);
mockMvc.perform(get(uri))
.andExpect(status().isOk())
.andDo(print())
.andExpect(content().contentType(TestUtil.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.accounts", hasSize(2)))
.andExpect(jsonPath("$.accounts[*].username",
hasItems(endsWith(accountOne.getUsername()), endsWith(accountTwo.getUsername()))))
.andExpect(jsonPath("$.accounts[*].email",
hasItems(endsWith(accountOne.getEmail()), endsWith(accountTwo.getEmail()))));
}
我的问题是,当我运行JUnit测试时,它会出现错误
org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.Pageable]: Specified class is an interface
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:99)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:142)
at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttribute(ServletModelAttributeMethodProcessor.java:80)
at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:102)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:622)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:167)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:155)
at de.campuz.platform.rest.controller.AccountControllerTestDoc.getAccountsTest(AccountControllerTestDoc.java:93)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.restdocs.JUnitRestDocumentation$1.evaluate(JUnitRestDocumentation.java:55)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
我添加了@EnableSpringDataWebSupport注释到我的web配置,但错误仍然存在。在控制器正常工作的情况下运行应用程序时,我将获得页面帐户作为JSON响应。但是我不知道如何测试我的控制器。
有没有人知道如何解决这个特定的问题或如何单元测试Spring MVC控制器返回页面内容一般?
我通过从Controller构造函数中删除Pageable Pageable来解决这个问题,因为无论如何我都不需要它。然后PagedResourcesAssembler汇编器抛出错误
org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.data.web.PagedResourcesAssembler]:
No default constructor found; nested exception is java.lang.NoSuchMethodException:
org.springframework.data.web.PagedResourcesAssembler.<init>()
我深入研究了ResourceAssembler的主题,并提出了以下解决方案:
控制器:
@RequestMapping(method=RequestMethod.GET)
public ResponseEntity<PagedResources<AccountResource>> getAccounts(
@RequestParam(value="name", required = false) String name,
@RequestParam(value="username", required = false) String username,
@RequestParam(value="email", required = false) String email,
@RequestParam(value="lastName", required = false) String lastName,
@RequestParam(value="size", required = true, defaultValue = "10") Integer size,
@RequestParam(value="page", required = true, defaultValue = "0") int page,
@RequestParam(value="sort", required = false, defaultValue = "username") String sort,
@RequestParam(value="direction", required = false, defaultValue = "asc") String direction,
UriComponentsBuilder uriBuilder,
HttpServletRequest request,
HttpServletResponse response) {
// Build page request
AccountList list = null;
Page<Account> resultPage = null;
Direction sortDirection = Direction.ASC;
if(direction.equals("desc")) {
sortDirection = Direction.DESC;
}
PageRequest pReq = new PageRequest(page, size, sortDirection, sort);
resultPage = accountService.findAll(pReq);
HateoasPageableHandlerMethodArgumentResolver resolver = new HateoasPageableHandlerMethodArgumentResolver();
PagedResourcesAssembler<Account> accountPageAssembler = new PagedResourcesAssembler<Account>(resolver, null);
return new ResponseEntity<PagedResources<AccountResource>>(accountPageAssembler.toResource(resultPage, new AccountResourceAsm()), HttpStatus.OK);
}
在这里,我用HateoasPageableHandlerMethodArgumentResolver创建了资源汇编器,将页面转换为我想要返回的PagedResource。
然后我终于可以成功运行控制器测试(如问题中所示)。
这个回答对我帮助很大,谢谢Oliver Gierke和Patrick Cornelissen。
遇到同样的问题,我想避免在控制器中"手动"获取PagedResourcesAssembler
。
将此添加到测试类中为我修复了它:
@Import(HateoasAwareSpringDataWebConfiguration.class)