Home > OS >  Spring Boot: Testing ResponseEntity Containing Java Time
Spring Boot: Testing ResponseEntity Containing Java Time

Time:12-09

I need to test a Rest API response body that holds a java.time.Instant field. Unfortunately, the test cannot be passed because of milliseconds difference between actual and expected timestamps. I'm just wondering how I can mock the system clock or somehow configure the test context to make the test pass:

Response body class:

public class ApiError {
    private HttpStatus httpStatus;
    private Instant timestamp;
    private List<ErrorDetail> errorDetails;

    public ApiError(HttpStatus httpStatus) {
        this.httpStatus = httpStatus;
        this.timestamp = Instant.now();
    }

// the rest of class is omitted for brevity
}

The test class:

@WebMvcTest(controllers = UserController.class)
class UserControllerTest {

    @Autowired MockMvc mockMvc;
    @Autowired ObjectMapper mapper;
    ApiError apiError;

    @Test
    public void givenBlankField_WhenRequestIsReceived_ThenApiErrorGenerated() throws Exception {
        SignUpRequest request = new SignUpRequest()
                .setFirstName(" ")  //validation error occurs
                .setLastName("Doe")
                .setPassword("123")
                .setConfirmPassword("123")
                .setEmail("[email protected]")
                .setConfirmEmail("[email protected]");

        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/api/users/signup")
                .content(mapper.writeValueAsString(request))
                .contentType(MediaType.APPLICATION_JSON))
                .andExpect(MockMvcResultMatchers.status().isBadRequest()).andReturn();

        String actualResponseBody = result.getResponse().getContentAsString();

        // Excpected response body:
        apiError = new ApiError(HttpStatus.BAD_REQUEST);
        FieldValidationErrorDetail errorDetail = new FieldValidationErrorDetail.Detail()
                .field("firstName").message("{NotBlank.firstName}").rejectedValue(" ").build();
        apiError.setErrorDetails(List.of(errorDetail));
        String expectedResponseBody = mapper.writeValueAsString(apiError);

        assertEquals(expectedResponseBody, actualResponseBody); //fails due to milliseconds difference between actual timestamp and expected timestamp
    }
}

CodePudding user response:

Explanation

Here you are instantiating the timestamp field at two different times and comparing them. They will always fail to match.

Solution

I would recommend avoiding the instantiation of new ApiError(HttpStatus.BAD_REQUEST) in your test and simply verifying each field individually. For the timestamp field, just verify that it is set to a non-null value or if you want to get pedantic, verify that it has a value within the last X number of seconds instead of the precise millisecond validation that you are currently checking.

Alternative Solution (Hacky Workaround)

If you want to continue validation a JSON string against a JSON string, simply convert the response body into an object and steal it's timestamp into your comparison object.

  • Related