AssertJ Exception Assertions 가이드

yesjuhee·2024년 10월 31일

Java 공부

목록 보기
14/17

아래 사이트에 게시된 글을 정리/번역해 작성한 글입니다. 작성 중에 생략된 내용이 있을 수 있습니다.
https://www.baeldung.com/assertj-exception-assertion

1. Overview

AssertJ의 excption 전용 assertion을 살펴보자.

2. Without AssetJ

try {
    // ...
} catch (Exception e) {
    // assertions
}

AssertJ를 사용하지 않는다면 위처럼 테스트코드를 작성할 수 있다. 하지만 만약 예외가 발생하지 않은 경우, 테스트가 의도와 다르게 성공으로 표시된다.

3. With AssertJ

Java 8을 사용하면 AssertJ와 람다 표현식을 이용해 예외에 대한 어설션을 쉽게 수행할 수 있다.

3.1 Using assertThatThrownBy()

IndexOutOfBoundsException 예외를 발생하는 예시를 살펴보자. assertThatThrownBy() 메서드에 람다 표현식으로 예외를 던질 수 있는 메서드를 넘겨주고 있다.

assertThatThrownBy(() -> {
    List<String> list = Arrays.asList("String one", "String two");
    list.get(2);
}).isInstanceOf(IndexOutOfBoundsException.class)
  .hasMessageContaining("Index: 2, Size: 2");

다양한 표준 AssetJ 어설션을 연결해서 사용할 수 있다.

.hasMessage("Index: %s, Size: %s", 2, 2)
.hasMessageStartingWith("Index: 2")
.hasMessageContaining("2")
.hasMessageEndingWith("Size: 2")
.hasMessageMatching("Index: \\d+, Size: \\d+")
.hasCauseInstanceOf(IOException.class)
.hasStackTraceContaining("java.io.IOException");

3.2 Using assetThatExceptionOfType()

기본 아이디어는 위와 비슷하지만 제일 먼저 exception type을 명시한다.

assertThatExceptionOfType(IndexOutOfBoundsException.class)
  .isThrownBy(() -> {
      // ...
}).hasMessageMatching("Index: \\d+, Size: \\d+");

3.3 Using assertThatIOExcption() and Other Common Types

AssetJ는 기본 예외 타입에 대한 wrapper를 제공한다.

assertThatIOException().isThrownBy(() -> {
    // ...
});
  • assertThatIllegalArgumentException()
  • assertThatIllegalStateException()
  • assertThatIOException()
  • assertThatNullPointerException()

3.4 Separating the Exception From the Assertion

whenthen을 구분하기 위해 catchThrowable()을 이용해 다음과 같이 작성할 수 있다.

// when
Throwable thrown = catchThrowable(() -> {
    // ...
});

// then
assertThat(thrown)
  .isInstanceOf(ArithmeticException.class)
  .hasMessageContaining("/ by zero");

3.5 Asserting Fields of Custom Exception

AssertJ는 catchThrowableOfType() 메서드와 같이 custom exception의 필드를 검사할 수 있는 몇가지 편리한 방법을 제공한다.

다음과 같이 CityNotFoundException이라는 이름의 커스텀 예외를 예시로 들어보자.

public class CityNotFoundException extends RuntimeException {

    private String city;
    private String message;

    CityNotFoundException(String city, String message) {
        this.city = city;
        this.message = message;
    }

    // Getters

}

다음은 CityNotFoundException을 발생시키는 예시 메서드이다. 해당 예외는 citymessage 필드를 가지고 있다.

public final class CityUtils {

    private static final List<String> CITIES = Arrays.asList("Tamassint", "London", "Madrid", "New york");

    public static String search(String searchedCity) {
        return CITIES.stream()
          .filter(searchedCity::equals)
          .findFirst()
          .orElseThrow(() -> new CityNotFoundException(searchedCity, "The specified city is not found"));
    }
}

커스텀 예외의 필드를 검사할 수 있는 테스트 케이스는 다음과 같이 작성할 수 있다. catchThrowableOfType()을 통해 커스텀 예외를 캐치하고 assertThat() 으로 예외의 필드 값을 체크한다.

@Test
public void whenUsingCatchThrowableOfType_thenAssertField() {
    String givenCity = "Paris";
    CityNotFoundException exception = catchThrowableOfType(() -> CityUtils.search(givenCity), CityNotFoundException.class);

    assertThat(exception.getCity()).isEqualTo(givenCity);
    assertThat(exception.getMessage()).isEqualTo("The specified city is not found");
}

assertThatThrownBy()를 이용해서 동일한 테스트를 할 수 있다.

@Test
public void whenUsingAssertThatThrownBy_thenAssertField() {
    String givenCity = "Geneva";
    assertThatThrownBy(() -> CityUtils.search(givenCity)).isInstanceOf(CityNotFoundException.class)
      .extracting("city")
      .isEqualTo(givenCity);
}
profile
https://yesjuhee.tistory.com/

0개의 댓글