我正在针对REST控制器POST处理程序进行集成测试。好吧,我正在努力。
它给我HttpMessageNotReadableException异常:无法读取JSON:由于输入结束,没有内容要映射
这是我的控制器:
@Controller @RequestMapping("admin") public class AdminController { private static Logger logger = LoggerFactory.getLogger(AdminController.class); private static final String TEMPLATE = "Hello, %s!"; @Autowired private AdminService adminService; @Autowired private AdminRepository adminRepository; @RequestMapping(value = "crud", method = RequestMethod.POST, produces = "application/json; charset=utf-8") @ResponseBody public ResponseEntity<Admin> add(@RequestBody Admin admin, UriComponentsBuilder builder) { AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin())); Admin createdAdmin = Admin.fromEventAdmin(adminCreatedEvent.getEventAdmin()); HttpHeaders responseHeaders = new HttpHeaders(); responseHeaders.add("Content-Type", "application/json; charset=utf-8"); responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri()); return new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED); } @ExceptionHandler(HttpMessageNotReadableException.class) @ResponseBody public String handleException(HttpMessageNotReadableException e) { return e.getMessage(); } }
基本测试类:
@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration( classes = { ApplicationConfiguration.class, WebSecurityConfig.class, WebConfiguration.class, WebTestConfiguration.class }) @Transactional public abstract class AbstractControllerTest { @Autowired private WebApplicationContext webApplicationContext; @Autowired private FilterChainProxy springSecurityFilterChain; protected MockHttpSession session; protected MockHttpServletRequest request; protected MockMvc mockMvc; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).addFilters(this.springSecurityFilterChain).build(); } }
集成测试:
@Test public void testAdd() throws Exception { HttpHeaders httpHeaders = Common.createAuthenticationHeaders("stephane" + ":" + "mypassword"); this.mockMvc.perform( post("/admin/crud").headers(httpHeaders) .param("firstname", "Stephane") .param("lastname", "Eybert") .param("login", "stephane") .param("password", "toto") ).andDo(print()) .andExpect( status().isOk() ).andReturn(); }
控制台日志必须说些什么:
2013-11-04 19:31:23,168 DEBUG [HttpSessionSecurityContextRepository] SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@158ddda0: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@158ddda0: Principal: org.springframework.security.core.userdetails.User@552e813c: Username: stephane; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ADMIN' 2013-11-04 19:31:23,168 DEBUG [RequestResponseBodyMethodProcessor] Written [Could not read JSON: No content to map due to end-of-input at [Source: UNKNOWN; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input at [Source: UNKNOWN; line: 1, column: 1]] as "application/json;charset=utf-8" using [org.springframework.http.converter.StringHttpMessageConverter@10d328] 2013-11-04 19:31:23,169 DEBUG [TestDispatcherServlet] Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling 2013-11-04 19:31:23,169 DEBUG [TestDispatcherServlet] Successfully completed request 2013-11-04 19:31:23,169 DEBUG [ExceptionTranslationFilter] Chain processed normally 2013-11-04 19:31:23,169 DEBUG [SecurityContextPersistenceFilter] SecurityContextHolder now cleared, as request processing completed MockHttpServletRequest: HTTP Method = POST Request URI = /admin/crud Parameters = {firstname=[Stephane], lastname=[Eybert], login=[stephane], password=[toto]} Headers = {Content-Type=[application/json], Accept=[application/json], Authorization=[Basic c3RlcGhhbmU6bXlwYXNzd29yZA==]} Handler: Type = com.thalasoft.learnintouch.rest.controller.AdminController Method = public org.springframework.http.ResponseEntity<com.thalasoft.learnintouch.rest.domain.Admin> com.thalasoft.learnintouch.rest.controller.AdminController.add(com.thalasoft.learnintouch.rest.domain.Admin,org.springframework.web.util.UriComponentsBuilder) Async: Was async started = false Async result = null Resolved Exception: Type = org.springframework.http.converter.HttpMessageNotReadableException ModelAndView: View name = null View = null Model = null FlashMap: MockHttpServletResponse: Status = 200 Error message = null Headers = {Content-Type=[application/json;charset=utf-8], Content-Length=[254]} Content type = application/json;charset=utf-8 Body = Could not read JSON: No content to map due to end-of-input at [Source: UNKNOWN; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input at [Source: UNKNOWN; line: 1, column: 1] Forwarded URL = null Redirected URL = null Cookies = [] 2013-11-04 19:31:23,177 DEBUG [TransactionalTestExecutionListener] No method-level @Rollback override: using default rollback [true] for test context [TestContext@ce4625 testClass = AdminControllerTest, testInstance = com.thalasoft.learnintouch.rest.AdminControllerTest@1b62fcd, testMethod = testAdd@AdminControllerTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@9be79a testClass = AdminControllerTest, locations = '{}', classes = '{class com.thalasoft.learnintouch.rest.config.ApplicationConfiguration, class com.thalasoft.learnintouch.rest.config.WebSecurityConfig, class com.thalasoft.learnintouch.rest.config.WebConfiguration, class com.thalasoft.learnintouch.rest.config.WebTestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]]]
有什么线索吗?
我将.param()方法替换为.content()方法之一:
post("/admin/crud").headers(httpHeaders) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content("{ \"firstname\" : \"" + admin0.getFirstname() + "\", \"lastname\" : \"" + admin0.getLastname() + "\", \"email\" : \"" + admin0.getEmail() + "\", \"login\" : \"" + admin0.getLogin() + "\", \"password\" : \"" + admin0.getPassword() + "\", \"passwordSalt\" : \"" + admin0.getPasswordSalt() + "\" }") ).andDo(print()) .andExpect(status().isCreated()) .andExpect(jsonPath("$.firstname").value(admin0.getFirstname())) .andExpect(jsonPath("$.lastname").value(admin0.getLastname())) .andExpect(jsonPath("$.email").value(admin0.getEmail())) .andExpect(jsonPath("$.login").value(admin0.getLogin())) .andExpect(jsonPath("$.password").value(admin0.getPassword())) .andExpect(jsonPath("$.passwordSalt").value(admin0.getPasswordSalt())) .andReturn();
现在,它可以按预期工作。