Java – 单元测试中响应 JSON 的输出不正确

huangapple go评论68阅读模式
英文:

Java - Incorrect output for response JSON in unit test

问题

In your unit test, the issue seems to be related to the JSON representation of the UserAmountDTO object. Instead of returning the expected JSON representation, it's returning an empty string, which is causing the test to fail.

One potential reason for this behavior could be the usage of @JsonProperty(access = Access.WRITE_ONLY) on the amount field. This annotation is likely preventing the amount field from being included in the JSON representation when serializing the object, even if you set its value in your test.

To resolve this issue, you might consider removing @JsonProperty(access = Access.WRITE_ONLY) from the amount field in your UserAmountDTO class. This should ensure that the amount field is included in the JSON representation when you serialize the object in your test.

Here's the modified UserAmountDTO class without the @JsonProperty annotation:

@Getter
@Setter
@AllArgsConstructor
public class UserAmountDTO {
    public double amount;
    
    @JsonProperty(access = Access.READ_ONLY)
    public double balance;
}

With this change, the amount field should be included in the JSON representation when you serialize userAmountDTO in your test, and the test should work as expected.

英文:

I am testing my depositUserBalance endpoint controller and this is just a simple test but I am not sure why it is not getting the correct response JSON as compared to the one returned in my REST API.

// My Controller
@PutMapping("/api/deposit")
public ResponseEntity<UserAmountDTO> depositUserBalance(HttpServletRequest request,
                @RequestBody UserAmountDTO userAmountDTO) {
        Integer userId = (Integer) request.getAttribute("userId");
        userAmountDTO = userService.updateUserBalance(userId, userAmountDTO);
        return new ResponseEntity<>(userAmountDTO, HttpStatus.OK);
}
// My UserAmountDTO Data Transfer Object
@Getter
@Setter
@AllArgsConstructor
public class UserAmountDTO {
    
    @JsonProperty(access = Access.WRITE_ONLY)
    public double amount;

    @JsonProperty(access = Access.READ_ONLY)
    public double balance;

}
@Test
public void Test_DepositUserBalance() throws Exception {
    // Arrange
    UserAmountDTO userAmountDTO = new UserAmountDTO(2000.0, 3000.0);
    HttpServletRequest request = mock(HttpServletRequest.class);
    when(request.getAttribute("userId")).thenReturn(1);
    when(userService.updateUserBalance(1, userAmountDTO)).thenReturn(userAmountDTO);
    String requestBody = objectMapper.writeValueAsString(userAmountDTO);
    System.out.println("requestBody: " + requestBody);

    // Act
    MvcResult mvcResult = mockMvc.perform(put(DEPOSIT_PATH)
            .contentType(MediaType.APPLICATION_JSON)
            .content(requestBody).with(requestBuilder -> {
                requestBuilder.setAttribute("userId", 1);
                return requestBuilder;
            }))
            .andExpect(status().isOk())
            .andReturn();

    // Assert
    int status = mvcResult.getResponse().getStatus();
    String content = mvcResult.getResponse().getContentAsString();
    String expectedJson = String.format("{\"balance\":%.1f}", 3000.0);
    assertEquals(HttpStatus.OK.value(), status);
    assertEquals(expectedJson, content);
}

In my unit test, the requestBody was returned as balance here requestBody: {"balance":3000.0} when it should be amount because I set the @JsonProperty(acccess = Access.WRITE_ONLY) to amount.

The error from the test was org.opentest4j.AssertionFailedError: expected: [{"balance":3000.0}] but was: []. Why is it an empty string? When I tried it in the REST API on POSTMAN, it actually returned me this JSON balance amount. Coupled with the fact that I added @JsonProperty(acccess = Access.READ_ONLY) to balance.

答案1

得分: 1

关于REST控制器上的单元测试POST请求的更新

我成功解决了错误,简而言之,这是因为我向模拟的服务传递了一个不同的内存地址的对象。简单地说,when(userService.updateUserBalance(1, userAmountDTO)).thenReturn(userAmountDTO);,这是模拟userService.updateUserBalance方法的适当方式。

然而,在@Test**内部,userAmountDTO的内存地址可能会是@21835tj3之类的东西。在我的控制器中,userAmountDTO = userService.updateUserBalance(userId, userAmountDTO);,传递给userService.updateUserBalance方法的userAmountDTO的内存地址可能会不同,比如@21943jf3,这就是为什么它与单元测试中的模拟服务参数不匹配的原因。具有相同字段和值的对象并不意味着它们共享相同的引用,因此模拟的方法没有返回预期的值。

为了解决这个问题

使用ArgumentMatchers.any() Mockito来匹配UserAmountDTO类的任何对象。因此,在单元测试中更改模拟方法为when(userService.updateUserBalance(eq(1), ArgumentMatchers.any(UserAmountDTO))).thenReturn(userAmountDTO);

这通常发生在POST请求中,因为我们传递了一个反序列化的JSON对象。还要感谢@JorgeCampos支持调试过程。

英文:

UPDATE ON UNIT TESTING POST REQUEST ON RESTCONTROLLER

I managed to resolve the mistake and in summary it is because I was passing in an object to the mocked service a different memory address. To put it simply, when(userService.updateUserBalance(1, userAmountDTO)).thenReturn(userAmountDTO);, this is an appropriate way to mock the userService.updateUserBalance method.

However, inside the @Test, the userAmountDTO memory address could be something like @21835tj3. In my controller, userAmountDTO = userService.updateUserBalance(userId, userAmountDTO);, the memory address of userAmountDTO being passed into the userService.updateUserBalance method could be different like @21943jf3 which was why it does not match the mocked service arguments in the unit test. Objects with the same fields and values doesn't mean they share the same reference, thus the mocked method did not return the expected value.

To fix this:

Use the ArgumentMatchers.any() Mockito to match any object of the UserAmountDTO class. So, change the mocked method in the unit test to when(userService.updateUserBalance(eq(1), ArgumentMatchers.any(UserAmountDTO))).thenReturn(userAmountDTO);

This usually happens with POST requests as we pass in a deserialized JSON object. Also thanks to @JorgeCampos for supporting with the debug process.

huangapple
  • 本文由 发表于 2023年4月20日 00:26:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76056842.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定