Search code examples
javaimmutabilitydtojackson-databind

Setter in DTO just for integration testing?


I couldn't find the info I'm looking for hence posting here for suggestion and getting to know better approach.

I have an immutable DTO object like:

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDate;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AccountCreateDto {
    String name;
    Long accountNo;
    String email;
    LocalDate dob;
    String address;
    Long phone;
    Integer amount;
    LocalDate accountOpeningDate;
    Integer installmentAmount;
    Integer totalAmount;
    LocalDate installmentPaidDate;

    @JsonCreator
    public AccountCreateDto(
            @JsonProperty("name") String name,
            @JsonProperty("accountNo") Long accountNo,
            @JsonProperty("email") String email,
            @JsonProperty("dob") LocalDate dob,
            @JsonProperty("address") String address,
            @JsonProperty("phone") Long phone,
            @JsonProperty("amount") Integer amount,
            @JsonProperty("accountOpeningDate") LocalDate accountOpeningDate,
            @JsonProperty("installmentAmount") Integer installmentAmount,
            @JsonProperty("totalAmount") Integer totalAmount,
            @JsonProperty("installmentPaidDate") LocalDate installmentPaidDate
    ) {
        this.name = name;
        this.accountNo = accountNo;
        this.email = email;
        this.dob = dob;
        this.address = address;
        this.phone = phone;
        this.amount = amount;
        this.accountOpeningDate = accountOpeningDate;
        this.installmentAmount = installmentAmount;
        this.totalAmount = totalAmount;
        this.installmentPaidDate = installmentPaidDate;
    }
    // removing getters for brevity
}

Now I'm working on an integration test with testcontainer where I want the accountOpeningDate and installmentPaidDate to be dynamic value hence in order to set these values from Integration Tests, is it a good idea to add only 2 setters to this DTO which is only to be used for Integration Tests like below?

    public void setAccountOpeningDate(LocalDate accountOpeningDate) {
        this.accountOpeningDate = accountOpeningDate;
    }

    public void setInstallmentPaidDate(LocalDate installmentPaidDate) {
        this.installmentPaidDate = installmentPaidDate;
    }

Or is there a better approach than this? Looking for recommendations.

TA


Solution

  • It is not acceptable you will lose the immutability of the object. With immutable classes, we can’t modify the state but must create a new instance with the mutated state.
    The builder pattern is very useful in this case.
    Example:

    AccountCreateDto existingImmutableDTO = new AccountCreateDto("name", 1L, "name@aaa", LocalDate.now(), "Address", null, null, null, null, null, null );
            
    //change state of imuttable object, create new instance via builder
    AccountCreateDto modifiedImmutableDTO = new AccountCreateDtoBuilder(existingImmutableDTO).setAccountOpeningDate(LocalDate.now()).setInstallmentPaidDate(LocalDate.now()).build();
    
    public class AccountCreateDtoBuilder {
        private String name;
        private Long accountNo;
        private String email;
        private LocalDate dob;
        private String address;
        private Long phone;
        private Integer amount;
        private LocalDate accountOpeningDate;
        private Integer installmentAmount;
        private Integer totalAmount;
        private LocalDate installmentPaidDate;
    
        public AccountCreateDtoBuilder() {
            
        }
    
        public AccountCreateDtoBuilder(AccountCreateDto accountCreateDto) {
            this.name = accountCreateDto.getName();
            this.accountNo = accountCreateDto.getAccountNo();
            this.email = accountCreateDto.getEmail();
            this.dob = accountCreateDto.getDob();
            this.address = accountCreateDto.getAddress();
            this.phone = accountCreateDto.getPhone();
            this.amount = accountCreateDto.getAmount();
            this.accountOpeningDate = accountCreateDto.getAccountOpeningDate();
            this.installmentAmount = accountCreateDto.getInstallmentAmount();
            this.totalAmount = accountCreateDto.getTotalAmount();
            this.installmentPaidDate = accountCreateDto.getInstallmentPaidDate();
        }
    
        public AccountCreateDto build() {
            return new AccountCreateDto(name, accountNo, email, dob, address, phone, amount, accountOpeningDate, installmentAmount, totalAmount, installmentPaidDate);
        }
    
        public AccountCreateDtoBuilder setName(String name) {
            this.name = name;
            return this;
        }
    
        public AccountCreateDtoBuilder setAccountNo(Long accountNo) {
            this.accountNo = accountNo;
            return this;
        }
    
        public AccountCreateDtoBuilder setEmail(String email) {
            this.email = email;
            return this;
        }
    
        public AccountCreateDtoBuilder setDob(LocalDate dob) {
            this.dob = dob;
            return this;
        }
    
        public AccountCreateDtoBuilder setAddress(String address) {
            this.address = address;
            return this;
        }
    
        public AccountCreateDtoBuilder setPhone(Long phone) {
            this.phone = phone;
            return this;
        }
    
        public AccountCreateDtoBuilder setAmount(Integer amount) {
            this.amount = amount;
            return this;
        }
    
        public AccountCreateDtoBuilder setAccountOpeningDate(LocalDate accountOpeningDate) {
            this.accountOpeningDate = accountOpeningDate;
            return this;
        }
    
        public AccountCreateDtoBuilder setInstallmentAmount(Integer installmentAmount) {
            this.installmentAmount = installmentAmount;
            return this;
        }
    
        public AccountCreateDtoBuilder setTotalAmount(Integer totalAmount) {
            this.totalAmount = totalAmount;
            return this;
        }
    
        public AccountCreateDtoBuilder setInstallmentPaidDate(LocalDate installmentPaidDate) {
            this.installmentPaidDate = installmentPaidDate;
            return this;
        }
    }