아이템 35. 작명 패턴 대신 어노테이션을 사용하라.
35. 작명 패턴 대신 어노테이션을 사용하라.
1.5 버전 이전에는 작명 패턴(naming pattern) 사용함, 이에 따른 단점들…
- 정의된 메서드에 오타가 나면 친절하게 씹어먹음(ex> Junit
test
라는 이름을 prefix 사용하던 시절, 테스트 케이스 깨짐) - 특정 요소에 대해서만 적용 할수 없음
- 파라미터로 전달 할 수 없음
어노테이션을 이용한 해결책
표준 어노테이션 정의
import java.lang.annotation.*
/**
* 어노테이션이 붙은 메서드가 테스트 메서드임을 표시.
* 무인자(parameterless) 정적 메서드에만 사용가능
*/
@Retention(RegentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
@Retention(RegentionPolicy.RUNTIME)
:@Test
가 실행 시간(runtime)에도 유지되어야 하는 어노테이션이라고 정의함@Target(ElementType.METHOD)
:@Test
가 메서드 선언부에만 적용할 수 있는 어노테이션이라고 정의함
표준 어노테이션을 처리하는 코드
public class RunTests{
public static void main(String[] args){
int tests = 0;
int passed = 0;
Class testClass = Class.forName(args[0]);
for(Method m : testClass.getDeclaredMethods()){
if( m.isAnnotationPresent(Test.class)){
tests++;
try{
m.invoke(null);
passed++;
}catch(InvocationTargetException wrappedExc){
Throwable exc = wrappedExc.getCause();
System.out.println(m + " failed: " + exc);
}catch(Exception exception){
System.out.println("INVALID @Test: " + m);
}
}
}
System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);
}
}
배열 인자를 추가한 어노테이션
// 배열을 인자로 받는 어노테이션 자료형
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
Class<? extends Exception>[] value();
}
배열 인자를 받는 어노테이션의 사용
public class Sample{
@ExceptionTest(ArithmeticException.class)
public static void test1(){ // 이 테스트는 성공 해야 함
int i = 0;
i = i / i;
}
@ExceptionTest(ArithmeticException.class)
public static void test2(){ // 이 테스트는 실패 해야 함(엉뚱한 예외 발생)
int[] a = new int[0];
int i = a[1];
}
@ExceptionTest(ArithmeticException.class)
public static void test3(){ // 이 테스트는 실패 해야 함(예외가 발생하지 않음)
}
}
배열 인자 어노테이션을 처리하는 코드
public class RunTests{
public static void main(String[] args){
int tests = 0;
int passed = 0;
Class testClass = Class.forName(args[0]);
for(Method m : testClass.getDeclaredMethods()){
if( m.isAnnotationPresent(Test.class)){
tests++;
try{
m.invoke(null);
passed++;
}catch(Throwable wrappedExc){
Throwable exc = wrappedExc.getCause();
Class<? extends Excetpion>[] excTypes = m.getAnnotation(ExceptionTest.class).value();
int oldPassed = passed;
for (Class<? extends Exception> excType : excTypes){
if(excType.isInstance(exc)){
passed++;
break;
}
}
if( passed == oldPassed)
System.out.printf("Test %s failed: %s %n",m, exc);
}
}
}
System.out.println("Passed: %d, Failed: %d%n", passed, tests - passed);
}
}
결론
- 프로그래머가 소스 파일에 정보를 추가할 수 있도록 도와 주는 도구가 어노테이션 임
- 작명 패턴을 쓰지 말자.
- 특정 도구를 제공한다면 편의성을 위해서 어노테이션을 적극 활용하자.