AssertJ
는 더 다양한 assertion을 제공하는 자바 라이브러리이다.
공식 문서 : https://assertj.github.io/doc/
Junit5
에서 제공하는 Assertion method
가 존재하는 데, AssertJ
는 어떤 특징 때문에 추가적인 라이브러리를 사용하는 것일까?
AssertJ의 여러 메소드들을 연쇄적으로 호출해 코드를 작성할 수 있다. (메서드 체이닝)
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
public class SimpleAssertionsExample {
@Test
void a_few_simple_assertions() {
assertThat("The Lord of the Rings").isNotNull()
.startsWith("The")
.contains("Lord")
.endsWith("Rings");
}
}
가장 기본적인 검증 메서드이다.
@Test
void test() {
String value = "Royce";
assertThat(value).isEqualTo("Royce");
}
이름에서도 유추할 수 있듯이, equals()
연산을 활용한다.
만약, equals
를 재정의 하지 않은 객체의 동등성을 비교하고자 한다면 isEqualToComparingFieldByFieldRecursively()
를 사용할 순 있다. 근데 deprecated
되었으니, 아래와 같은 방식usingRecursiveComparison()
으로 좀더 유연하게 필드값을 활용하는 검증 메서드를 사용할 수 있다.
@Test
void test() {
Person value = new Person(20, "Royce");
// Deprecated
// assertThat(value).isEqualToComparingFieldByFieldRecursively(new Person(20, "Royce"));
assertThat(value).usingRecursiveComparison()
.isEqualTo(new Person(20, "Royce"));
}
객체 검증에 대해 다양한 assertions
을 제공한다. 메서드 체이닝을 활용하여 더 다양하고 구체적인 테스트를 고려해보자
@Test
void test() {
Person value = new Person(20, "Royce");
assertThat(value).isNotNull()
.isExactlyInstanceOf(Person.class)
.usingRecursiveComparison()
.isNotEqualTo(new Person(22, "Pooh"));
}
@Test
void test() {
List<String> list = List.of("A", "B", "C", "D");
assertThat(list)
.isNotNull()
.doesNotContainNull()
.doesNotContain("E")
.containsSequence("A", "B") // 순서 검증
.doesNotContainSequence("B", "A")
.startsWith("A")
.endsWith("C", "D")
.hasSize(4)
.containsOnlyOnce("A") // "A"가 한개만 존재하는지 검증
.contains("D");
}
객체 배열에 대하여 값을 테스트 하고 싶다면 extracting()
을 활용할 수 있다. 해당 객체의 필드 이름을 알아야 한다는 단점이 있지만, 테스트만을 위한 getter
를 추가하지 않아도 테스트할 수 있는 장점도 존재한다.
@Test
void test() {
List<Person> list = List.of(new Person("Royce"), new Person("Pooh"), new Person("Luka"));
assertThat(list).extracting("name")
.isNotNull()
.doesNotContainNull()
.doesNotContain("Jerry")
.containsSequence("Royce", "Pooh")
.startsWith("Royce")
.hasSize(3)
.contains("Luka")
.doesNotHaveDuplicates(); // 중복 체크
}
하나의 필드만 추출하는 케이스만 제공하진 않는다. tuple
을 활용하여 다양한 필드에 대한 검증도 지원한다
tuple
은org.assertj.core.api.Assertions.tuple
에 존재합니다.
@Test
void test() {
List<Person> list = List.of(
new Person("Royce", 20),
new Person("Pooh", 21),
new Person("Luka", 22)
);
assertThat(list).extracting("name", "age")
.isNotNull()
.doesNotContainNull()
.doesNotContain(tuple("Royce", 123))
.startsWith(tuple("Royce", 20))
.hasSize(3)
.contains(tuple("Royce", 20), tuple("Pooh", 21));
}
@Test
void test() {
List<Person> list = List.of(
new Person("Royce", 20),
new Person("Pooh", 21),
new Person("Luka", 22)
);
assertThat(list).filteredOn("age", 20) //age필드 값이 20인 조건으로 필터
.hasSize(1)
.extracting("name") // 이름 추출
.containsOnly("Royce");
}
@Test
void test() {
List<Person> list = List.of(
new Person("Royce", 20),
new Person("Pooh", 21),
new Person("Luka", 22)
);
assertThat(list).filteredOn(person -> person.getAge() > 20) // 람다를 넣을 수 있다
.hasSize(2)
.extracting("name")
.containsOnly("Pooh", "Luka");
}
@Test
void test() {
Throwable thrown = AssertionsForClassTypes.catchThrowable(() -> {
throw new Exception("boom!");
});
assertThat(thrown).isInstanceOf(Exception.class)
.hasMessageContaining("boom");
}
위 코드와 같이 직접 Throwable
객체를 생성할 수 있지만, assertThatThrownBy()
를 통해 예외 객체를 생성하지 않고 좀 더 가독성 높은 테스트 코드를 구성할 수 있다.
@Test
void test() {
assertThatThrownBy(() -> {
throw new Exception("boom!");
}).isInstanceOf(Exception.class)
.hasMessageContaining("boom");
}
+ 추가적으로, Java의 표준 예외를 위한 메서드도 제공한다.
@Test
void test() {
assertThatNullPointerException().isThrownBy(() -> {
throw new NullPointerException("NPE!");
}).withMessage("NPE!");
}
@Test
void test() {
Map<String, String> results = new HashMap<>();
results.put("Royce", "10000원");
results.put("Pooh", "꽝");
results.put("Luca", "50000원");
assertThat(results)
.hasSize(3)
.containsEntry("Royce", "10000원") // Map에 존재하는 entry 검증
.extractingByKey("Royce") // Key값으로 get
.isEqualTo("10000원");
}
Predicate instance assertions
@Test
void test() {
Predicate<Integer> predicate = power -> power > 4;
assertThat(predicate)
.accepts(5, 6, 7, 8)
.rejects(1, 2, 3);
}
@Test
void test() {
int a = 20;
assertThat(a)
.isBetween(19, 20)
.isStrictlyBetween(19, 21)
.isLessThanOrEqualTo(20)
.isEven();
}
이 외에도 다양한 검증 메서드를 제공한다. 잘 찾아보고,, 잘 활용해보자