Hamcrest에서 Custom Matcher를 구현하는 방법을 소개합니다.
Hamcrest는 containsString()
, closeTo()
등과 같이 다양한 Matcher를 제공합니다. 하지만, 기본적으로 제공하는 Matcher들로 구현하기 어려운 테스트 케이스가 있습니다.
Hamcrest는 다음과 같은 abstract 클래스를 제공하며, 이 클래스를 구현하여 Custom Matcher를 만들 수 있습니다.
- TypeSafeMatcher
- TypeSafeDiagnosingMatcher
프로젝트 의존성 설정
프로젝트가 Gradle을 사용하는 경우, build.gradle
에서 아래와 같이 java-hamcrest
를 추가합니다.
dependencies {
testImplementation 'org.hamcrest:java-hamcrest:2.0.0.0'
}
Custom Matcher 구현 (TypeSafeMatcher)
TypeSafeMatcher를 구현하여 Custom Matcher를 만들 수 있습니다.
TypeSafeMatcher를 상속하면 아래 두개 메소드를 오버라이드 해야 합니다.
public class IsInteger extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String item) {
// return true if it matches
}
@Override
public void describeTo(Description description) {
// description for failure message
}
}
- matchesSafely : 인자로 전달되는 item이 어떤 조건에 일치하는지를 boolean으로 리턴합니다. true가 리턴되면 테스트는 패스합니다.
- describeTo : 테스트가 실패할 때 보여지는 내용으로, 테스트가 성공하려면 이 객체가 어떤 값이 되어야 하는지에 대한 메시지를 설정합니다.
문자열이 Integer인지 테스트하는 Matcher
아래 IsInteger 클래스는 문자열이 Integer인지 확인하는 Matcher입니다.
matchesSafely()
에서는 단순히 Integer.parseInt()
으로 Integer인지 아닌지 체크하였습니다.
describeTo()
에서는 문자열이 Integer로 구성되어야 한다는 메시지를 입력하였습니다.
public class IsInteger extends TypeSafeMatcher<String> {
@Override
protected boolean matchesSafely(String str) {
try {
Integer.parseInt(str);
return true;
} catch (NumberFormatException e) {
return false;
}
}
@Override
public void describeTo(Description description) {
description.appendText("A String of Integer");
}
public static Matcher<String> isInteger() {
return new IsInteger();
}
}
위에서 구현한 Matcher는 다음과 같이 assertThat과 함께 사용할 수 있습니다. 두번째 인자로 Matcher를 전달할 때, new IsInteger()
로 Matcher 객체를 생성하여 전달하면 됩니다.
@Test
public void testCustomMatcher_isInteger1() {
String num = "1234";
assertThat(num, new IsInteger());
}
객체를 생성하여 전달하는 가독성이 좋지 않기 때문에, 다음과 같이 Custom Matcher 객체를 생성하여 리턴하는 static 메소드를 IsInteger 클래스를 추가하였습니다.
public static Matcher<String> isInteger() {
return new IsInteger();
}
이제 이 메소드로 아래와 같이 간결하게 Custom Matcher를 assertThat()
에 전달할 수 있습니다.
@Test
public void testCustomMatcher_isInteger2() {
String num = "1234";
assertThat(num, isInteger());
}
실패 메시지
아래 테스트에서 1234.56
은 Integer가 아니기 때문에 실패하게 됩니다.
@Test
public void testCustomMatcher_isInteger3() {
String notNum = "1234.56";
assertThat(notNum, isInteger());
}
테스트가 실패하면 아래와 같은 실패 메시지를 출력합니다. Expected:
다음에 출력되는 메시지는 describeTo()
에서 입력한 문자열이 됩니다.
Expected: A String of Integer
but: was "1234.56"
다른 Matcher와 함께 사용
Custom Matcher는 is()
, not()
등의 기본적으로 제공하는 Matcher들과 함께 사용할 수 있습니다.
@Test
public void testCustomMatcher_isInteger4() {
String notNum = "1234.56";
assertThat(notNum, not(isInteger()));
}
Custom Matcher 구현 (TypeSafeDiagnosingMatcher)
이번에는 TypeSafeDiagnosingMatcher 클래스를 구현하여 Custom Matcher를 만들 것입니다. TypeSafeDiagnosingMatcher는 TypeSafeMatcher보다 좀 더 자세한 실패 메시지를 설정할 수 있습니다.
Integer가 짝수인지 테스트하는 Matcher
이번에는 Integer가 짝수인지 확인하는 IsEven이라는 Matcher를 구현합니다.
public class IsEven extends TypeSafeDiagnosingMatcher<Integer> {
@Override
protected boolean matchesSafely(Integer integer, Description description) {
description.appendText("was ").appendValue(integer)
.appendText(", which is an Odd number");
return integer % 2 == 0;
}
@Override
public void describeTo(Description description) {
description.appendText("An Even Number");
}
public static Matcher<Integer> isEven() {
return new IsEven();
}
}
TypeSafeDiagnosingMatcher의 경우, 아래 두개의 메소드를 구현하면 됩니다.
TypeSafeMatcher는 matchesSafely()
의 인자로 Description을 전달하지 않지만, 여기서는 전달합니다.
- matchesSafely(Integer integer, Description description)
- describeTo(Description description)
matchesSafely()
의 구현을 보면, description에 메시지를 입력합니다. 이 메시지는 테스트가 실패할 때만 출력됩니다.
@Override
protected boolean matchesSafely(Integer integer, Description description) {
description.appendText("was ").appendValue(integer)
.appendText(", which is an Odd number");
return integer % 2 == 0;
}
describeTo()
는 TypeSafeMatcher처럼 구현하면 됩니다.
실패 메시지
아래 테스트는 13이 홀수이기 때문에, 실패하게 됩니다.
@Test
public void testCustomMatcher_isEven2() {
Integer num2 = 13;
assertThat(num2, isEven());
}
테스트해보면, 실패 메시지는 다음과 같이 출력됩니다.
matchesSafely()
에서 설정한 메시지가 was <13>, which is an Odd number
처럼 출력되는 것을 확인할 수 있습니다.
Expected: An Even Number
but: was <13>, which is an Odd number
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 가져오기