개발그래머
AssertJ 라이브러리 메서드 정리 본문
목표
- 최근 테스트 코드를 작성하면서 여러 라이브러리들의 assert가 있어서 어떤 게 어떤 라이브러리에 속한 것이고 어떤 게 어떤 부분인지 헷갈렸다.
- 그래서 AssertJ와 Hamcrest중 그래도 많이 사용하는 AssertJ에 대해 정리하고 넘어가려고 한다.
- 정리할 내용은 https://assertj.github.io/doc/#assertj-core-simple-example 공식 문서를 기반으로 정리할 것이다.
- 테스트 코드는 예전 객체지향과 사실과 오해라는 책을 공부하면서 만든 엘리스, 트럼프 클래스에 대해 테스트 코드를 작성해 볼 것이다.
AssertJ Core
- AssertJ Core 라이브러리는 자바 8 이상의 버전을 요구한다
- 스프링부트에서는 자동적으로 AssertJ Core 라이브러리를 spirng-boot-starter-test에 포함되어있다
//maven
<properties>
<assertj.version>3.24.2</assertj.version>
</properties>
//gradle
ext['assertj.version'] = '3.24.2'
- 위와 같이 AssertJ Core의 버전을 조정할 수 있다
// all
import static org.assertj.core.api.Assertions.*;
// or
import static org.assertj.core.api.Assertions.assertThat; // main one
import static org.assertj.core.api.Assertions.atIndex; // for List assertions
import static org.assertj.core.api.Assertions.entry; // for Map assertions
import static org.assertj.core.api.Assertions.tuple; // when extracting several properties at once
import static org.assertj.core.api.Assertions.fail; // use when writing exception tests
import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown; // idem
import static org.assertj.core.api.Assertions.filter; // for Iterable/Array assertions
import static org.assertj.core.api.Assertions.offset; // for floating number assertions
import static org.assertj.core.api.Assertions.anyOf; // use with Condition
import static org.assertj.core.api.Assertions.contentOf; // use with File assertions
- AssertJ import 하는 법
assertThat(alice.getHeight()).isEqualTo(height);
then(alice.getHeight()).isEqualTo(height);
- BDD style의 assertions도 사용할 수 있다.
- assertThat 대신 then을 사용함
as() = assertion에 설명을 추가함
assertThat(alice.getHeight()).as("앨리스의 키").isEqualTo(11);
- as()를 사용하여 해당 단언(assertion)에 설명을 줄 수 있다.
overridingErrorMessage() or withFailMessage()
Alice alice = new Alice(height, passage);
Alice ali = new Alice(150, Place.BEAUTIFUL_GARDEN);
assertThat(alice.getHeight()).withFailMessage("should be %s", alice).isEqualTo(ali);
assertThat(alice.getHeight()).overridingErrorMessage("should be %s", alice).isEqualTo(ali);
- AssertJ는 유용한 오류 메시지를 주기 위해 노력하지만 overridingErrorMessage() 또는 withFailMessage()로 변경할 수 있음
assertThat(alice.getPlace() == Place.BEAUTIFUL_GARDEN).withFailMessage(() -> "expecting place is beautiful garden").isTrue();
assertThat(alice.getPlace() == Place.BEAUTIFUL_GARDEN).overridingErrorMessage(() -> "expecting place is beautiful garden").isTrue();
- 오류메시지를 작성하는데 비용이 많이 드는 경우 String 대신
Supplier<String>
을 사용하면 단언(assertion)이 실패한 경우에만 메시지가 작성됨
avoiding incorrect usage(잘못된 사용 피하기)
// Bad case
assertThat(actual.equals(expected));
// Good case
assertThat(actual).isEqualTo(expected);
assertThat(actual.equals(expected)).isTrue();
// Bad case
assertThat(1 == 2);
// Good case
assertThat(1).isEqualTo(2);
assertThat(1 == 2).isTrue();
- 단언을 호출하는 것을 잊으면 안 된다
- assertThat()에 전달만 하고 나중에 단언을 호출하는 것을 잊는 것임
// Bad case
assertThat(actual).isEqualTo(expected).as("description");
assertThat(actual).isEqualTo(expected).describedAs("description");
// Good case
assertThat(actual).as("description").isEqualTo(expected);
assertThat(actual).describedAs("description").isEqualTo(expected);
- as()를 단언 이후에 하면 안 된다.
// Bad case
assertThat(actual).isEqualTo(expected).overridingErrorMessage("custom error message");
assertThat(actual).isEqualTo(expected).withFailMessage("custom error message");
// Good case
assertThat(actual).overridingErrorMessage("custom error message").isEqualTo(expected);
assertThat(actual).withFailMessage("custom error message").isEqualTo(expected);
- overridingErrorMessage()와 withFailMessage()를 단언 이후에 하면 안 된다.
// Bad case
assertThat(actual).isEqualTo(expected).usingComparator(new CustomComparator());
// Good case
assertThat(actual).usingComparator(new CustomComparator()).isEqualTo("a");
- comparator를 세팅하는 것을 단언 이후에 하면 안 된다.
Common assertions(공통 검증)
주요 메서드
isEqualTo : 객체나 값이 주어진 값과 동일한지 확인(equals() 비교)
@Test
void isEqualTo() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(height).isEqualTo(160);
assertThat(passage).isEqualTo(Place.PASSAGE);
}
isNotEqualTo : 객체나 값이 주어진 값과 다른지 확인
@Test
void isNotEqualTo() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(height).isNotEqualTo(11);
assertThat(passage).isNotEqualTo(Place.BEAUTIFUL_GARDEN);
}
isNull : 객체가 null인지 확인
@Test
void isNull() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(alice.getKey()).isNull();
}
isNotNull : 객체가 null이 아닌지 확인
@Test
void isNotNull() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
alice.get(new Key(30));
assertThat(alice.getKey()).isNotNull();
}
isSameAs : 객체가 주어진 객체와 동일한 객체인지 확인(== 비교)
@Test
void isSameAs() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
Alice alice2 = alice;
//Verifies that the actual value is the same as the given one, ie using == comparison.
assertThat(alice).isSameAs(alice2);
}
isNotSameAs : 객체가 주어진 객체와 다른 객체인지 확인
@Test
void isNotSameAs() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
Alice clone = new Alice(height, passage);
assertThat(alice).isNotSameAs(clone);
}
isInstanceOf : 객체가 주어진 클래스의 인스턴스인지 확인
@Test
void isInstanceOf() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(alice).isInstanceOf(Alice.class);
}
Object assertions(객체 검증)
주요 메서드
hasFieldOrProperty : 실제 객체에 지정된 필드 또는 속성이 있는지 확인
@Test
void hasFieldOrProperty() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(alice).hasFieldOrProperty("height");
assertThat(alice).hasFieldOrProperty("place");
}
hasFieldOrPropertyWithValue : 실제 객체에 지정된 값을 가진 지정된 필드 또는 속성이 있음을 확인
@Test
void hasFieldOrPropertyWithValue() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(alice).hasFieldOrPropertyWithValue("height", height);
assertThat(alice).hasFieldOrPropertyWithValue("place", passage);
}
extracting : 테스트 중인 객체에서 지정된 필드, 속성의 값을 목록으로 추출하며 이 새 목록은 테스트 중인 객체가 됨
@Test
void extracting() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
assertThat(alice).extracting("height", "place")
.containsExactly(height, passage);
}
String/CharSequence assertions(문자열 검증)
주요 메서드
startsWith : 문자열이 주어진 접두사로 시작하는지 확인
@Test
void startsWith() {
String name = "Alice";
assertThat(name).startsWith("Ali");
}
endsWith : 문자열이 주어진 접미사로 끝나는지 확인
@Test
void endsWith() {
String name = "Alice";
assertThat(name).endsWith("ce");
}
contains : 문자열이 주어진 부분 문자열을 포함하는지 확인
@Test
void contains() {
String name = "Alice";
assertThat(name).contains("ic");
}
matches : 문자열이 정규 표현식과 일치하는지 확인
@Test
void matches() {
String name = "Alice";
assertThat(name).matches(".....");
}
Iterable and array assertions(컬렉션과 배열 검증)
https://www.javadoc.io/doc/org.assertj/assertj-core/latest/org/assertj/core/api/AbstractIterableAssert.html#method.summary
https://www.javadoc.io/doc/org.assertj/assertj-core/latest/org/assertj/core/api/AbstractObjectArrayAssert.html#method.summary
주요 메서드
contains : 컬렉션이 주어진 요소를 포함하는지 확인
@Test
void collectionContains() {
TrumpShape[] shapes = TrumpShape.values();
List<TrumpShape> shapeList = Arrays.stream(shapes).collect(Collectors.toList());
assertThat(shapes).contains(TrumpShape.CLOVER);
assertThat(shapeList).contains(TrumpShape.CLOVER);
}
containsExactly : 컬렉션이 주어진 요소를 정확히 순서대로 포함하는지 확인
@Test
void containsExactly() {
TrumpShape[] shapes = TrumpShape.values();
List<TrumpShape> shapeList = Arrays.stream(shapes).collect(Collectors.toList());
assertThat(shapes).containsExactly(TrumpShape.SPADE, TrumpShape.HEART, TrumpShape.DIAMOND, TrumpShape.CLOVER);
assertThat(shapeList).elements(0,1,2,3).contains(TrumpShape.SPADE, TrumpShape.HEART, TrumpShape.DIAMOND, TrumpShape.CLOVER);
}
hasSize : 컬렉션이 주어진 크기와 일치하는지 확인
@Test
void hasSize() {
TrumpShape[] shapes = TrumpShape.values();
List<TrumpShape> shapeList = Arrays.stream(shapes).collect(Collectors.toList());
assertThat(shapes).hasSize(shapes.length);
assertThat(shapeList).hasSize(shapeList.size());
}
isEmpty : 컬렉션이 비어 있는지 확인
@Test
void isEmpty() {
List<Object> emptyList = List.of();
TrumpShape[] shapes = TrumpShape.values();
List<TrumpShape> shapeList = Arrays.stream(shapes).collect(Collectors.toList());
assertThat(emptyList).isEmpty();
assertThat(shapes).isNotEmpty();
assertThat(shapeList).isNotEmpty();
}
Exception assertions(예외 검증)
주요 메서드
isInstanceOf: 코드 실행 시 발생한 예외가 주어진 예외 클래스의 인스턴스인지 확인
@Test
void exceptionIsInstanceOf() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
Throwable thrown = catchThrowable(() -> alice.pass(new Door(120)));
assertThat(thrown).isInstanceOf(IllegalStateException.class);
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> alice.pass(new Door(120)))
.isInstanceOf(IllegalStateException.class);
}
hasMessage: 예외의 메시지가 주어진 문자열과 일치하는지 확인
@Test
void hasMessage() {
int height = 160;
Place passage = Place.PASSAGE;
Alice alice = new Alice(height, passage);
Throwable thrown = catchThrowable(() -> alice.pass(new Door(120)));
assertThat(thrown).hasMessage("키가 40보다 작아야합니다.");
}
'Unit Test' 카테고리의 다른 글
TDD(실전! 스프링부트 상품-주문 API 개발로 알아보는 TDD) (1) | 2023.03.21 |
---|