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.