JUnit 테스트의 가독성을 높일 수 있도록 Hamcrest에서 제공하는 몇 가지 Matcher 활용법에 대해 소개한다.
0. 준비
우선, 최신 버전의 hamcrest 라이브러리를 받는다. (현재 최신 버전은 2.2)
참고로 스프링에서는 기본적으로 assertj와 함께 해당 라이브러리를 제공한다.
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
그다음 assertThat + hamcrestMatcher 조합을 통해 가독성 있는 테스트를 해본다.
assertThat의 정적 메서드 파라미터의 첫 번째 인자는 검증하고자 하는 값, 두 번째는 Matcher를 사용한다.
* 여기서 assertThat은 hamcrest 패키지에 있는 assertThat을 사용한다.
public static <T> void assertThat(T actual, Matcher<? super T> matcher) {
assertThat("", actual, matcher);
}
1. equalTo
equalTo는 해당 Matcher는 비교 기준으로 equals() 메서드를 사용해서 '실제 값이 예상 값과 동일한지 여부를 확인'한다.
@Test
void testEqualTo() {
Shiba shiba = Shiba.builder()
.name("흑시바")
.build();
assertThat(shiba.getName(), equalTo("흑시바"));
}
만약 실제 값이 예상 값과 서로 다르면 테스트가 실패하며 AssertionError 메시지를 통해 왜 실패했는지 확인할 수 있다.
@Test
void testEqualTo() {
Shiba shiba = Shiba.builder()
.name("흑시바")
.build();
assertThat(shiba.getName(), equalTo("적시바"));
}
equalTo는 동등성 비교로 테스트 하기 때문에 특정 필드로 두 개의 객체가 동일하다고 판단하는 경우(값 객체 등)는 equals를 별도로 구현하지 않으면 테스트에 실패하게 된다.
예를 들어, 만약 id가 동일한 Shiba 객체가 동일하다고 판단하는데 equals를 구현하지 않는다면 하기 테스트처럼 실패하게 된다.
@Test
void testEqualToObjet() {
Shiba shiba1 = Shiba.builder()
.id(1L)
.name("흑시바")
.build();
Shiba shiba2 = Shiba.builder()
.id(1L)
.name("흑시바")
.build();
assertThat(shiba1, equalTo(shiba2));
}
그러므로 특정 필드로 객체의 동등성을 판단하는 경우에는 equals를 구현하고 테스트를 진행하자.
equalTo는 또한 '자바 배열 혹은 컬렉션 객체를 비교할 때'도 유용하게 사용할 수 있다.
- 비교하는 배열 혹은 컬렉션의 값이 일치하는 경우, 테스트에 성공한다.
@Test
void testEqualToArray() {
String[] shiba1 = {"시바견", "귀여운", "볼살"};
String[] shiba2 = {"시바견", "귀여운"};
assertThat(shiba1, equalTo(shiba2));
}
@Test
void testEqualToList() {
List<String> shiba1 = Arrays.asList("시바견", "귀여운", "볼살");
List<String> shiba2 = Arrays.asList("시바견", "귀여운", "볼살");
assertThat(shiba1, equalTo(shiba2));
}
- 비교하는 배열 혹은 컬렉션의 값이 다른 경우에는, 테스트에 실패한다.
@Test
void testFailEqualToArray() {
String[] shiba1 = {"시바견", "귀여운", "볼살"};
String[] shiba2 = {"시바견", "귀여운"};
assertThat(shiba1, equalTo(shiba2));
}
@Test
void testFailEqualToList() {
List<String> shiba1 = Arrays.asList("시바견", "귀여운", "볼살");
List<String> shiba2 = Arrays.asList("시바견", "귀여운");
assertThat(shiba1, equalTo(shiba2));
}
2. is
is는 '단순하게 가독성을 높이는 역할을 수행'한다.
단지 넘겨받은 Matcher를 반환하기만 하고 아무것도 하지 않는 코드이다.
@Test
void testEqualToObjet() {
Shiba shiba1 = Shiba.builder()
.id(1L)
.name("흑시바")
.build();
Shiba shiba2 = Shiba.builder()
.id(1L)
.name("흑시바")
.build();
assertThat(shiba1, is(equalTo(shiba2)));
}
3. not
'어떤 것을 부정하는 단언을 만드는 경우' not 매처를 사용한다.
@Test
void testNotMatcher() {
List<String> shiba1 = Arrays.asList("시바견", "귀여운", "볼살");
List<String> shiba2 = Arrays.asList("시바견", "귀여운");
assertThat(shiba1, not(equalTo(shiba2)));
}
4. nullValue, notNullValue
'null 값이거나 null 값이 아닌 값을 검사하는 경우' 사용한다.
@Test
void testNullValueMatcher() {
assertThat(null, nullValue());
}
@Test
void testNotNullValueMatcher() {
assertThat("흑시바", notNullValue());
}
5. startsWith
'특정 문자열로 시작하는지 검사하는 경우' 사용한다.
@Test
void testStartsWithMatcher() {
assertThat("shiba-holic", startsWith("shiba"));
}
6. closeTo
'부동소수점 수를 비교하는 경우' 사용한다.
자바에서 부동소수점 타입(float, double)으로 비교할 때 근사치로 구해야하는 값들이 존재한다.
따라서, 일반적인 equalTo Matcher를 사용해서 비교하는 경우 테스트에 실패할 수 있다.
@Test
void testFailNumberTest() {
assertThat(7.33*6, equalTo(43.98));
}
이런 경우, closeTo Matcher를 사용해서 두 수가 벌어질 수 있는 오차의 허용 범위를 지정해야 한다.
@Test
void testCloseToMatcher() {
assertThat(7.33*6, closeTo(43.98, 0.0004));
}
7. sameInstance
'동일한 인스턴스인지 확인할 때' 사용한다.
@Test
void testSameInstance() {
Shiba shiba1 = Shiba.builder().name("흑시바").build();
Shiba shiba2 = Shiba.builder().name("흑시바").build();
assertThat(shiba1, not(sameInstance(shiba2)));
}
8. allOf
'모든 Matcher 값이 일치하는지 여부를 확인할 때' 사용한다.
@Test
void testallOf() {
List<String> shiba1 = Arrays.asList("시바견", "귀여운", "사랑스러운");
assertThat(shiba1, allOf(hasItem("시바견"), hasItem("귀여운")));
}
9. anyOf
'하나 이상의 Matcher 값이 일치하는지 여부를 확인할 때' 사용한다.
@Test
void testanyOf() {
List<String> shiba1 = Arrays.asList("시바견", "귀여운", "사랑스러운");
assertThat(shiba1, anyOf(hasItem("흑시바"), hasItem("는"), hasItem("시바견")));
}
10. equalToIgnoringCase
'대소문자 구분 없이 동일한 문자열인지 판단할 때' 사용한다.
@Test
void testEqualToIgnoringCase() {
String testString = "Shiba is Black";
assertThat(testString, equalToIgnoringCase("shiba is black"));
}
11. either
'여러 Matcher 중 일치하는 Matcher가 있는지 확인할 때' 사용한다. or를 활용할 때 유용하다.
@Test
void testEqualToIgnoringCase() {
String testString = "Shiba is Black";
assertThat(testString, either(containsString("Red"))
.or(containsString("Shiba"))
.or(containsString("Color")));
}
12. both
'여러 Matcher가 동시에 일치하는지 확인할 때' 사용한다. and를 활용할 때 유용하다.
@Test
void testBoth() {
String testString = "Shiba is Black";
assertThat(testString, both(containsString("Shiba"))
.and(containsString("Black")));
}
REFERENCE
https://www.javadoc.io/doc/org.hamcrest/hamcrest/latest/org/hamcrest/Matchers.html
Matchers - hamcrest 2.2 javadoc
Latest version of org.hamcrest:hamcrest https://javadoc.io/doc/org.hamcrest/hamcrest Current version 2.2 https://javadoc.io/doc/org.hamcrest/hamcrest/2.2 package-list path (used for javadoc generation -link option) https://javadoc.io/doc/org.hamcrest/hamcr
www.javadoc.io
'Spring > Test' 카테고리의 다른 글
flatExtracting 활용해서 내부 리스트 내용 검증하기 (0) | 2023.12.03 |
---|---|
전체 통합 테스트 시간 속도를 증가시키는 Spring Test Context Caching (0) | 2023.11.08 |
JPA Auditing @createdDate 테스트 코드 작성하기 (0) | 2023.10.30 |
@TempDir 활용해서 파일 테스트 코드 작성하기 (0) | 2023.09.25 |
데이터베이스 통합 테스트 코드 작성 Tip (0) | 2023.05.06 |
댓글