assertj의 usingRecursiveComparison 를 사용하면 원하는 값들로만 비교하여 isEqualTo를 사용할 수 있다.
체스 미션에서 Dao 테스트를 작성할 때 일이다. id 값이 없는 Line을 생성하여 Dao의 save 메서드를 호출하여 받은 Auto increment된 id가 포함된 Line객체가 같은 필드를 갖고 있는지 검증하는 테스트를 작성하려 하였다. Line 객체는 id, name, color 필드를 가지고 있다.
코드는 다음과 같았다.
@Test
@DisplayName("Line 을 저장한다.")
void save() {
//given
Line line = new Line("7호선", "khaki");
//when
Line actual = lineDao.save(line);
//then
assertThat(actual.getName()).isEqualTo(line.getName());
assertThat(actual.getColor()).isEqualTo(line.getColor());
}
아~ 불편하다. 그러면 필드가 3개면 3개의 assert문, N개면 N개의 속성을 비교해야할까? 자. 그러면 equals를 재정의 하면 어떨까?
Entity는 담고 있는 값만 같다면 같은 객체로 간주할 수 있는(동등) VO(Value Object)와 다르다. 식별성을 가지고 객체 주기 동안 유지되는 연속성이 핵심이다. 우리의 코드에서는 id 필드가 다르더라도 테스트를 위해 name, color의 동등성을 비교하기 위해 equals와 hashcode를 재정의할 경우 엔티티의 연속성을 위반하게된다.
private void hasSameNameAndColor(Line actual, Line expected) {
return actual.getName().equals(expected.getName()) && actual.getColor().equals(expected.getColor());
하... assertThat 코드가 깔끔해지기는 했어도 필드가 늘어나면 메소드가 지저분해지는 건 똑같다. 우리에게 구원책은 없을까???😭😭😭
assertj의 usingRecursiveComparison 를 사용하자!!!다행히 우리의 assertj는 은총을 가지고 계신다. usingRecursiveComparison 메서드를 사용하면 재귀적으로 객체의 필드를 순회하며 동등성 비교를 해준다. 따라서 우리는 객체의 필드가 변경될 때마다 테스트를 수정할 필요가 없어진다!!! 이 얼마나 기적같은 일인가!!!
百聞不如一見! 위의 메서드와 같은 기능을 하는 코드는 아래와 같다.
private void checkHasSameNameAndColor(Line actual, Line expected) {
assertThat(actual).usingRecursiveComparison()
.ignoringFields("id") // 비교하지 않을 필드를 지정할 수 있다.
// .ignoringActualNullField Null인 필드를 비교하지 않을 수 있다.
.isEqualTo(expected);
}
이 얼마나 신성한 코드인가! 우리는 자유롭게 손쉽게 비교하지 않을 필드를 지정할 수도, Null이 있는 값은 비교하지 않을 수도 있다!!!
이로써 우리의 테스트 코드는 Line의 변경에도 유연하게 대응할 수 있는 구조가 되었다. 기쁘도다 기쁘도다!!!🤸♂️🤸♂️🌟
우리의 assertj는 테스트를 쉽게 하기 위한 여러가지 기능들을 제공하고 있다. 하... 내가 꼭 이런 테스트 코드를 짜야 해...? 라고 고민하는 판다같은 사람이라면 assertj가 제공하는 기능들을 탐색해보자. 그대에게 은총이 내릴지어니.
우리의 사랑 코니
에릭 에반스, 도메인 주도 설계, 위키북스