spring - MocMVC 给出 HttpMessageNotReadableException

标签 spring unit-testing spring-mvc

我仍在学习测试方法,我正在尝试让 MockMvc 测试为我工作。这是一个简单的 REST Controller ,此时仅使用帖子中 json 中的信息进行一些身份验证。我实际上已经实现了代码,所以我知道它正在工作,因为我得到了正确输入的正确响应和我放在一起的错误消息,两者都是 json 格式。我的问题是,即使实际代码有效,测试仍会因 HttpMessageNotReadableException 而失败,所以我假设我的测试设置不正确。你们能提供的任何帮助都会很棒。

这是我的 Controller

@Controller
public class RequestPaymentController {
protected final Log logger = LogFactory.getLog(getClass());
private PaymentService paymentService;
private LoginService loginService;

@Autowired
public void setPaymentService(PaymentService paymentService){
    this.paymentService =  paymentService;
}
@Autowired
public void setLoginService(LoginService loginService){
    this.loginService =  loginService;
}

@RequestMapping(value = "/requestpayment", method = RequestMethod.POST, headers="Accept=application/json")
@ResponseBody
public ResponseEntity<PaymentResult> handleRequestPayment(@RequestBody PaymentRequest paymentRequest, HttpServletRequest request, HttpServletResponse response, BindingResult result) throws Exception{
    ResponseEntity<PaymentResult> responseEntity = null;
    new LoginValidator().validate(paymentRequest, result);
    boolean valid = loginService.isLoginValid(paymentRequest, result);
    if (valid){
      responseEntity = setValidResponse(paymentRequest);
    }else {
        throw new TumsException("exception message");

    }
    return responseEntity;
}


private ResponseEntity<PaymentResult> setValidResponse(PaymentRequest paymentRequest){
    PaymentResult paymentResult = paymentService.getResults(paymentRequest);

    return new ResponseEntity<PaymentResult>(paymentResult, HttpStatus.OK);
}


}

这是我的测试代码:
public class RequestPaymentControllerTest {

PaymentService mockPaymentService;
RequestPaymentController requestPaymentController;
HttpServletRequest mockHttpServletRequest;
HttpServletResponse mockHttpServletResponse;
PaymentRequest mockPaymentRequest;
BindingResult mockBindingResult;
LoginService mockLoginService;
PaymentResult mockPaymentResult;
MockMvc mockMvc;


@Before
public void setUp() throws Exception {
    mockPaymentService = createMock(PaymentService.class);
    mockHttpServletRequest = createMock(HttpServletRequest.class);
    mockHttpServletResponse = createMock(HttpServletResponse.class);
    mockPaymentRequest = createMock(PaymentRequest.class);
    requestPaymentController = new RequestPaymentController();
    mockBindingResult = createMock(BindingResult.class);
    mockLoginService = createMock(LoginService.class);
    requestPaymentController.setPaymentService(mockPaymentService);
    mockPaymentResult = createMock(PaymentResult.class);
    mockMvc = MockMvcBuilders.standaloneSetup(new RequestPaymentController()).build();

}

@After
public void tearDown() throws Exception {
    mockPaymentService = null;
    mockHttpServletRequest = null;
    mockHttpServletResponse = null;
    mockPaymentRequest = null;
    requestPaymentController = null;
    mockBindingResult = null;
    mockLoginService = null;
    mockPaymentResult = null;
    mockMvc = null;
}


@Test
public void testHandleRequestPayment() throws Exception{
    initializeStateForHandleRequestPayment();
    createExpectationsForHandleRequestPayment();
    replayAndVerifyExpectationsForHandleRequestPayment();

}



private void initializeStateForHandleRequestPayment(){

}

private void createExpectationsForHandleRequestPayment(){
    mockPaymentRequest.getServiceUsername();
    expectLastCall().andReturn("testuser");
    mockPaymentRequest.getServicePassword();
    expectLastCall().andReturn("password1!");
    mockLoginService.isLoginValid(mockPaymentRequest,mockBindingResult);
    expectLastCall().andReturn(true);
    mockPaymentService.getResults(mockPaymentRequest);
    expectLastCall().andReturn(mockPaymentResult);
}

private void replayAndVerifyExpectationsForHandleRequestPayment() throws Exception{
    replay(mockPaymentService, mockBindingResult, mockHttpServletRequest, mockHttpServletResponse, mockPaymentRequest, mockLoginService);
    requestPaymentController.setLoginService(mockLoginService);
    requestPaymentController.handleRequestPayment(mockPaymentRequest, mockHttpServletRequest, mockHttpServletResponse, mockBindingResult);
    mockMvc.perform(post("/requestpayment")
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON))
            .andDo(print())
            .andExpect(status().isBadRequest());
    verify(mockPaymentService, mockBindingResult, mockHttpServletRequest, mockHttpServletResponse, mockPaymentRequest, mockLoginService);

}
}

andDo(print()) 的结果是:
MockHttpServletRequest:
     HTTP Method = POST
     Request URI = /requestpayment
      Parameters = {}
         Headers = {Content-Type=[application/json], Accept=[application/json]}

         Handler:
            Type = portal.echecks.controller.RequestPaymentController
          Method = public org.springframework.http.ResponseEntity<portal.echecks.model.PaymentResult> portal.echecks.controller.RequestPaymentController.handleRequestPayment(portal.echecks.model.PaymentRequest,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,org.springframework.validation.BindingResult) throws java.lang.Exception

  Resolved Exception:
            Type = org.springframework.http.converter.HttpMessageNotReadableException

    ModelAndView:
       View name = null
            View = null
           Model = null

        FlashMap:

MockHttpServletResponse:
          Status = 400
   Error message = null
         Headers = {}
    Content type = null
            Body = 
   Forwarded URL = null
  Redirected URL = null
         Cookies = []

Process finished with exit code 0

正如您所看到的,当我期望一个错误的请求状态时,测试通过了,但是我已经进行了日志记录并且我知道我发回的 ResponseBody 状态为 200。就像我说的,这是我第一次使用 MockMvc,所以我认为我没有设置正确的东西。有什么建议?

最佳答案

HttpMessageNotReadableException

Thrown by HttpMessageConverter implementations when the read method fails.



您还会在响应中收到 400 Bad Request。这应该都告诉您,您没有发送服务器期望的内容。您的服务器期望什么?
@RequestMapping(value = "/requestpayment", method = RequestMethod.POST, headers="Accept=application/json")
@ResponseBody
public ResponseEntity<PaymentResult> handleRequestPayment(@RequestBody PaymentRequest paymentRequest, HttpServletRequest request, HttpServletResponse response, BindingResult result) throws Exception{

这里的主要内容是 @RequestBody带注释的参数。所以你告诉你的服务器尝试反序列化 PaymentRequest HTTP POST 请求正文中的实例。

所以让我们看看你提出的请求
mockMvc.perform(post("/requestpayment")
        .contentType(MediaType.APPLICATION_JSON)
        .accept(MediaType.APPLICATION_JSON))
        .andDo(print())
        .andExpect(status().isBadRequest());

我没有看到您为请求提供正文。应该有 content(String) 调用那里的某个地方来设置 POST 请求的内容。此内容应该是 PaymentRequest 的 JSON 序列化.

请注意,因为您使用的是 StandaloneMockMvcBuilder ,您可能需要设置 HttpMessageConverter实例自己,即。 MappingJackson2HttpMessageConverter序列化和反序列化 JSON。

请注意 BindingResult参数应紧跟在与其相关的参数之后。像这样
@RequestMapping(value = "/requestpayment", method = RequestMethod.POST, headers="Accept=application/json")
@ResponseBody
public ResponseEntity<PaymentResult> handleRequestPayment(@Valid @RequestBody PaymentRequest paymentRequest, BindingResult result, HttpServletRequest request, HttpServletResponse response) throws Exception{

不要忘记 @Valid .

请注意,这
requestPaymentController.setLoginService(mockLoginService);
requestPaymentController.handleRequestPayment(mockPaymentRequest, mockHttpServletRequest, mockHttpServletResponse, mockBindingResult);

MockMvc完全无关测试你在做什么。

关于spring - MocMVC 给出 HttpMessageNotReadableException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21648921/

相关文章:

node.js - Mocha 单元测试 Mongoose 模型

spring - 将项目从spring boot部署到tomcat,post表单出错

java - PageNotFound - noHandlerFound 在 DispatcherServlet 中未找到带有 URI [/SpringSecWebApp/welcome] 且名称为 'mvc-dispatcher' 的 HTTP 请求的映射

java - Spring MVC Web 应用程序中映射到 HTTP 路径的处理程序方法不明确

java - spring事务管理器可以管理2个事务吗?

java - Spring Boot POSTed JSON 数据验证

mysql - Spring Hibernate 配置问题

java - 尝试使用 PowerMock 模拟静态系统类会给出 VerifyError

java - IllegalStateException 运行 Grails 服务单元测试

java - 持久化具有外键字段的实体时出错