After reading about Value Objects, I think they're pretty cool and should be used, but I am not sure if I am doing it the right way.
Let's assume that I have a simple DTO to create a user, which contains information that should be validated (e.g., the email must be valid, the birthdate cannot be in the future, etc.) from a technical point of view. At the same time, I have a business requirement such as the user can't be younger than 14 years old, and I don't think that hardcoding this into the Birthdate class is a good idea. I think it would be better to move this validation to another service.
public class CreateUserPayloadDto {
@JsonPropery("email")
Email email; // user's email
@JsonPropery("birthdate")
Birthdate birthdate; // user's birthdate
}
If I use Value Objects in the DTO, I can't test negative cases properly (for example, if the birthdate is in the future, then BAD REQUEST must be returned).
I have come up with three solutions:
- Do not use Value Objects but use Java Bean Validation (then convert it to a POJO with Value Objects inside).
- Use Value Objects and do not write tests for negative cases.
- Create a separate DTO that uses primitives but is the same as the DTO with Value Objects, and test it this way. See example of code below
public class CreateUserPayloadDto {
@JsonPropery("email")
String email; // user's email
@JsonPropery("birthdate")
String birthdate; // user's birthdate
}
If you need more info, I will provide it as soon as I can. Thank you!
UPD:
Here is an example of my integration test:
@SpringBootTest
@AutoConfigureWebTestClient
public CreateUserEndpointTest {
@Autowired
WebTestClient webTestClient;
@Test
public void shouldReturn400BadRequestIfBirthdateIsInTheFuture() {
final CreateUserPayloadDto body = CreateUserPayloadDto.builder()
// I can't do this, because Birthdate cannot be instantiated
// since it is invalid!
.birthdate(Birthdate.of(LocalDate.now().plusYears(1)))
.build();
final WebTestClient.ResponseSpec responseSpec = sendRequest(body);
responseSpec.expectStatus().isBadRequest();
}
}