AssertJ

zwundzwzig·2023년 11월 13일
1

Test

목록 보기
2/2

JUnit5만으로 유닛 테스트를 작성하기 보다 AssertJ와 함께 좀더 편리한 기능 구현이 가능하다고 한다.

AssertJ

import static org.assertj.core.api.Assertions.*;

JUnit이 있음에도 AssertJ가 사용되는 이유는 보다 풍부한 표현을 가능케함이다. 예시를 보자.

assertNotEquals("무한", "도전");
assertThat("도전").isNotEqualTo("무한");

기존 JUnit의 Assertions는 actual과 expected의 순서가 헷갈려(비록 IDE가 있긴 하지만) 개발자가 실수를 저지를 수도 있는 환경이다.

반면 assertThat 메서드로 대표되는 AssertJ의 메서드는 타겟으로 하는 데이터를 미리 뽑아놓고 체이닝을 통해 보다 안전하게 개발자에게 테스트 환경을, 그것도 여러번 제공해준다. 아래와 같이 말이다.

assertThat(ye)
	.isNotEmpty()
    .contains("ye")
    .doesNotContain("Kardashian")
    .startsWith("Kanye")
    .endsWith("West")
    .isNotEquals("!")
  	.isEqualTo("Kanye West");

as메서드를 활용해서 에러가 발생하기 전 테스트에 대한 결과를 찍어볼 수도 있다.

assertThat(ye.getAge()).as("check %s's age", ye.getName()).isEqualTo(100);

어쩌면 JUnit5보다 더 람다식에 특화돼 여러 체이닝과 필터링을 동시에 작업할 수 있다.

// filters use introspection to get property/field values
assertThat(fellowshipOfTheRing).filteredOn("race", HOBBIT)
                               .containsOnly(sam, frodo, pippin, merry);

// nested properties are supported
assertThat(fellowshipOfTheRing).filteredOn("race.name", "Man")
                               .containsOnly(aragorn, boromir);

// you can apply different comparison
assertThat(fellowshipOfTheRing).filteredOn("race", notIn(HOBBIT, MAN))
                               .containsOnly(gandalf, gimli, legolas);

assertThat(fellowshipOfTheRing).filteredOn("race", in(MAIA, MAN))
                               .containsOnly(gandalf, boromir, aragorn);

assertThat(fellowshipOfTheRing).filteredOn("race", not(HOBBIT))
                               .containsOnly(gandalf, boromir, aragorn, gimli, legolas);

// you can chain multiple filter criteria
assertThat(fellowshipOfTheRing).filteredOn("race", MAN)
                               .filteredOn("name", not("Boromir"))
                               .containsOnly(aragorn);

배열에서 특정 값이 존재하는지, 존재하지 않는 지 등의 여부도 테스트할 수 있다.

assertThat(fellowshipOfTheRing).extracting("name", String.class)
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas")
                               .doesNotContain("Sauron", "Elrond");
 

import static org.assertj.core.api.Assertions.tuple;

// extracting name, age and and race.name nested property
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
                               .contains(tuple("Boromir", 37, "Man"),
                                         tuple("Sam", 38, "Hobbit"),
                                         tuple("Legolas", 1000, "Elf"));

예외처리도 가능하다

public class ExceptionSyntax {
    @Test
    @DisplayName("NullPoint 예외 처리")
    void nullPoint() {
        assertThatNullPointerException().isThrownBy(() -> {
                    throw new NullPointerException("null!");
                }).withMessage("%s!", "null")
                .withMessageContaining("nu")
                .withNoCause();
    }

    @Test
    @DisplayName("IllegalArgument 예외 처리")
    void illegalArgs() {
        assertThatIllegalArgumentException().isThrownBy(() -> {
                    throw new IllegalArgumentException("Illegal args!");
                }).withMessage("%s!", "Illegal args")
                .withMessageContaining("Il")
                .withNoCause();
    }

    @Test
    @DisplayName("IllegalState 예외 처리")
    void illegalState() {
        assertThatIllegalStateException().isThrownBy(() -> {
                    throw new IllegalStateException("Illegal state!");
                }).withMessage("%s!", "Illegal state")
                .withMessageContaining("Il")
                .withNoCause();
    }

    @Test
    @DisplayName("IO 예외 처리")
    void io() {
        assertThatIOException().isThrownBy(() -> {
                    throw new IOException("IO!");
                }).withMessage("%s!", "IO")
                .withMessageContaining("I")
                .withNoCause();
    }
}

참고 자료🔗

profile
개발이란?

0개의 댓글