FireDrago

[Assertj] equals, getter 없이 테스트코드 작성하기 (usingRecursiveComparison) 본문

프로그래밍/Java

[Assertj] equals, getter 없이 테스트코드 작성하기 (usingRecursiveComparison)

화이용 2024. 11. 18. 19:07

테스트만을 위한 코드 없애고 싶다.

public class Product {

    private final String name;
    private final int price;
    private int quantity;
    private Promotion promotion;

    public Product(String name, int price, int quantity, Promotion promotion) {
        this.name = name;
        this.price = price;
        this.quantity = quantity;
        this.promotion = promotion;
    }

     ...
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Product product = (Product) o;
        return price == product.price && quantity == product.quantity && Objects.equals(name,
            product.name) && Objects.equals(promotion, product.promotion);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, price, quantity, promotion);
    }
}

테스트 코드를 작성할때, 테스트를 위해서 getter, 나 equals, hashcode를 오버라이딩 했었다.
테스트만을 위한 코드를 작성하는것은 코드의 복잡성을 증가시킨다. 

 

Assertj 의 usingRecursiveComparison()

Person sherlock = new Person("Sherlock", 1.80);
sherlock.home.ownedSince = new Date(123);
sherlock.home.address.street = "Baker Street";
sherlock.home.address.number = 221;

Person sherlock2 = new Person("Sherlock", 1.80);
sherlock2.home.ownedSince = new Date(123);
sherlock2.home.address.street = "Baker Street";
sherlock2.home.address.number = 221;

// 재귀적으로 객체의 모든 필드값을 비교한다.
assertThat(sherlock).usingRecursiveComparison()
                    .isEqualTo(sherlock2);

// 동일성 비교, equals,hashcode 오버라이딩이 없다면 false 
assertThat(sherlock).isEqualTo(sherlock2);

Assertj 의 usingRecursiveComparison() 메서드를 사용하면 equals 없이 객체의 동등성을 비교할 수 있다.

이 메서드는 객체의 모든  계층적 필드를 비교한다. 이를 '재귀적 비교'라고 한다.

메서드의 '재귀적 호출'과는 살짝 다른 개념이다. 객체의  하위 객체 필드까지 모두 비교한다. 

테스트만을 위한 equals, hashcode 오버라이딩 없이 테스트를 실행할 수 있게 된다.

 

Doctor drSheldon = new Doctor("Sheldon Cooper", true);
Doctor drLeonard = new Doctor("Leonard Hofstadter", true);
Doctor drRaj = new Doctor("Raj Koothrappali", true);

Person sheldon = new Person("Sheldon Cooper", false);
Person leonard = new Person("Leonard Hofstadter", false);
Person raj = new Person("Raj Koothrappali", false);
Person howard = new Person("Howard Wolowitz", false);

List<Doctor> doctors = list(drSheldon, drLeonard, drRaj);
List<Person> people = list(sheldon, leonard, raj);

// hasPhd 필드는 비교에서 제외한다.
RecursiveComparisonConfiguration configuration 
	= RecursiveComparisonConfiguration.builder()
                                      .withIgnoredFields("hasPhd")
                                      .build();
                                      
// Iterator (컬렉션)을 재귀적으로 비교할때 사용하는 메서드
assertThat(doctors).usingRecursiveFieldByFieldElementComparator(configuration)
                   .contains(sheldon);

RecursiveComparisonConfiguration 을 통해 특정 필드값을 비교에서 제외할 수 있다.

usingRecursiveFieldByFieldElementComparator()  List,Map등의 컬렉션내의 요소들도 재귀적 비교 할  수 있다.

 

재귀적 비교는 순환 참조의 문제가 있거나, 성능상의 단점이 있으므로 이점을 유의하여 사용해야 한다.