Hamcrest는 Junit의 Assert framework입니다. Hamcrest는 다양한 Matcher를 제공하며, 간결한 코드로 객체의 상태를 테스트할 수 있습니다. 또한, 테스트가 실패되었을 때, 어떤 이유로 테스트가 실패하였는지 자세한 Failure 메시지를 출력합니다.
Hamcrest라는 용어는 단순히 Matchers의 알파벳 위치를 변경하여 만들어졌습니다.
Matcher
Matcher는 match operation을 수행하는 객체입니다.
다음과 같이 assertThat()
에 Object와 Matcher를 인자로 전달하면, Matcher는 Object가 예상하는 조건에 부합하는지 확인합니다. Matcher의 결과에 따라서 테스트가 성공하거나 실패합니다.
public void assertThat(Object o, Matcher matcher){
...
}
Hamcrest를 사용하는 이유
Junit의 Assert를 이용한 테스트와 Hamcrest를 이용한 테스트를 비교하면서, Hamcrest를 사용하는 이유에 대해서 알아보겠습니다.
- Failure 메시지의 가독성
- 테스트 코드의 가독성
- 다양한 Matcher 제공
Failure 메시지의 가독성
아래 코드는 Junit에서 제공하는 기본적인 Assert로 변수 a와 b가 다른지 체크하는 테스트입니다.
@Test
public void test_using_junit() {
int a = 10;
int b = 10;
assertNotEquals(a, b);
}
위 테스트는 당연히 실패하게 되는데, 실패 메시지를 보면 뭐가 잘못되었다는 것인지 한눈에 들어오지 않습니다. 로그와 함께 코드를 보면, a와 b의 값이 같아서 테스트가 실패되었구나 이해하게 됩니다.
expected: not equal but was: <10>
org.opentest4j.AssertionFailedError: expected: not equal but was: <10>
위의 코드는 다음과 같이 Hamcrest를 사용하는 테스트로 구현할 수도 있습니다.
@Test
public void test_using_hamcrest() {
int a = 10;
int b = 10;
assertThat(a, is(not(equalTo(b))));
}
이 테스트도 당연히 실패하게 되는데, 실패 로그를 보면 위의 로그보다 이해하기가 편합니다.
Expected: is not <10>
but: was <10>
테스트 코드의 가독성 (1)
assertNotEquals()
는 Junit에서 기본적으로 제공하는 Assert입니다. 이 Assert는 인자로 전달된 a와 b가 다른지 확인합니다. 간단한 코드이기 때문에 이해하는데 어렵지는 않습니다.
assertNotEquals(a, b);
다음은 Hamcrest를 사용하여 위와 동일한 조건을 체크하는 테스트 코드입니다. 코드를 보면 위와 다르게 완벽한 영어 문장이 됩니다.
assertThat(a, is(not(equalTo(b))));
위의 코드는 지나치게 완벽한 문장으로 만들어져있어서 약간 가독성이 떨어진다고 생각할 수 있는데요.
다음과 같이 is()
를 제거해도 결과는 동일하며, 좀 더 코드가 간결해 보입니다.
assertThat(a, not(equalTo(b)));
테스트 코드의 가독성 (2)
다음과 같이 str 변수가 3개의 조건을 모두 만족하는지 테스트하는 코드를 작성할 수 있습니다. 물론, 3개의 assert로 각각 테스트하는 것이 좋지만, 1개의 assert로 구현해야하는 상황이 있다고 가정했습니다.
public void test_allOf() {
String str = "MyTest";
boolean result = str.equals("MyTest")
&& str.startsWith("My")
&& str.contains("Test");
assertTrue(result);
}
Hamcrest에서는 allOf()
Matcher를 제공하며, 인자로 전달되는 모든 Matcher가 패스해야 테스트가 성공합니다. 즉, allOf()
는 논리 연산자에서 AND를 의미합니다.
&&
대신에 all Of
라는 표현이 들어가서 코드를 이해하는데 도움이 될 수 있습니다.
@Test
public void test_allOf() {
String str = "MyTest";
assertThat(str, allOf(is("MyTest"),
startsWith("My"),
containsString("Test")));
}
반대로 논리연산자 OR에 해당하는 Matcher는 anyOf()
입니다. 인자로 전달되는 Matcher 중에 하나만 패스되면 테스트가 패스됩니다.
assertThat(str, anyOf(is("MyTest"),
startsWith("Me"),
containsString("Test")));
다양한 Matcher 제공
a와 b의 절대값 차이가 0.5 이하라는 것을 테스트하려면 다음과 같이 assertTrue로 구현할 수 있습니다.
@Test
public void test_closeTo() {
double a = 10.9;
double b = 10.0;
assertTrue(Math.abs(a-b) < 0.5);
}
하지만 이 코드는 가독성도 좋지 못하고, 실패했을 때 다음과 같이 왜 실패했는지 이해하기 어려운 로그를 출력합니다.
expected: <true> but was: <false>
Expected :true
Actual :false
Hamcrest에는 closeTo()
라는 Matcher를 제공하고, 이것을 이용하여 절대값의 차이가 0.5 이하인지 테스트 할 수 있습니다.
@Test
public void test_using_hamcrest3() {
double a = 10.9;
double b = 10.0;
assertThat(a, closeTo(b, 0.5));
}
테스트가 실패했을 때도, 왜 실패했는지에 대한 로그가 출력됩니다.
Expected: a numeric value within <0.5> of <10.0>
but: <10.9> differed by <0.40000000000000036> more than delta <0.5>
Hamcrest에는 closeTo()
외에도 다양한 Matcher들을 제공합니다. API에 대한 자세한 내용은 Hamcrest JavaDoc을 참고하시면 됩니다.
- allOf, anyOf
- not, is
- hasEntry, hasKey, hasValue
- closeTo
- greaterThan, greaterThanOrEqualTo, lessThan, lessThanOrEqualTo
- equalToIgnoringCase, equalToIgnoringWhiteSpace
- containsString, endsWith, startsWith
Related Posts
- Java - Unsupported class file major version 61 에러
- Java - String.matches()로 문자열 패턴 확인 및 다양한 예제 소개
- Java - 문자열 공백제거 (trim, replace)
- Java - replace()와 replaceAll()의 차이점
- Java - ArrayList 초기화, 4가지 방법
- Java - 배열 정렬(Sorting) (오름차순, 내림차순)
- Java - 문자열(String)을 비교하는 방법 (==, equals, compare)
- Java - StringBuilder 사용 방법, 예제
- Java - 로그 출력, 파일 저장 방법 (Logger 라이브러리)
- Java IllegalArgumentException 의미, 발생 이유
- Java - NullPointerException 원인, 해결 방법
- Seleninum의 ConnectionFailedException: Unable to establish websocket connection 해결
- Java - compareTo(), 객체 크기 비교
- Java - BufferedWriter로 파일 쓰기
- Java - BufferedReader로 파일 읽기
- Java charAt() 함수 알아보기
- Java - BigInteger 범위, 비교, 연산, 형변환
- Java contains()로 문자(대소문자 X) 포함 확인
- Java - Set(HashSet)를 배열로 변환
- Java - 문자열 첫번째 문자, 마지막 문자 확인
- Java - 문자열 한글자씩 자르기
- Java - 문자열 단어 개수 가져오기
- Java - 1초마다 반복 실행
- Java - 배열을 Set(HashSet)로 변환
- Java - 여러 Set(HashSet) 합치기
- Java - 명령행 인자 입력 받기
- Java - 리스트 역순으로 순회, 3가지 방법
- Java - 특정 조건으로 리스트 필터링, 3가지 방법
- Java - HashMap 모든 요소들의 합계, 평균 계산
- Java - 특정 조건으로 HashMap 필터링
- Java - 싱글톤(Singleton) 패턴 구현
- Java - 숫자 왼쪽에 0으로 채우기
- Java - String 배열 초기화 방법
- Java - 정렬된 순서로 Map(HashMap) 순회
- Java - HashMap에서 key, value 가져오기