Skip to content

Latest commit

Β 

History

History
303 lines (204 loc) Β· 9.69 KB

item39.md

File metadata and controls

303 lines (204 loc) Β· 9.69 KB

ITEM 39 λͺ…λͺ… νŒ¨ν„΄λ³΄λ‹€ μ—λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜λΌ

λͺ…λͺ… νŒ¨ν„΄ - JUnit3

  • JUnit3 의 경우 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€μ˜ 이름은 test 둜 μ‹œμž‘ν•΄μ•Ό ν•œλ‹€.
  • test 둜 μ‹œμž‘ν•΄μ•Ό ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ‘œ μΈμ‹ν•œλ‹€.
  • TestCase 클래슀λ₯Ό 상속받아야 ν•œλ‹€.
import junit.framework.*;
 
public class TestSample extends TestCase {
       public TestSample(String name){  super(name); }
 
       public void setUp(){}
 
       public void tearDown(){}
 
		// λͺ…λͺ…νŒ¨ν„΄ - ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λŠ” test 둜 μ‹œμž‘
       public void test01(){
              //ν…ŒμŠ€νŠΈ μ½”λ“œ
       }
 
       public static Test suite (){
              return new TestSuite( TestSample.class );
       }
 
       public static void main(String args[]){
              TesrFinder.run(TestSample.class,args);
       }
}
[λ ˆν•„λ¦¬μ•„μ˜ μž‘λ™μ‚¬λ‹ˆ :: λ‹¨μœ„ν…ŒμŠ€νŠΈ JUNIT (3)]
(https://repilria.tistory.com/315)


λͺ…λͺ…νŒ¨ν„΄μ˜ 단점

  • μ˜€νƒ€κ°€ λ‚˜λ©΄ 인식을 λͺ»ν•œλ‹€.
    • 인식을 λͺ»ν•˜λ©΄ 였λ₯˜λ©”세지도 λœ¨μ§€ μ•Šμ„ 것이고, ν…ŒμŠ€νŠΈκ°€ ν†΅κ³Όν–ˆλ‹€κ³  잘λͺ» 인식할 수 μžˆλ‹€.
  • μ˜λ„ν•œ κ³³μ—μ„œλ§Œ 쓰일 것이라 보μž₯ν•  수 μ—†λ‹€.
    • μ‚¬μš©λ²•μ„ 잘 λͺ¨λ₯΄λŠ” μ‚¬μš©μžκ°€ λ©”μ„œλ“œκ°€ μ•„λ‹Œ ν΄λž˜μŠ€μ— Test λͺ…λͺ…νŒ¨ν„΄μ„ μ μš©ν•˜κ³  κ·Έ 클래슀의 ν…ŒμŠ€νŠΈ μΌ€μ΄μŠ€λ“€μ΄ μ‹€ν–‰λ˜κΈΈ κΈ°λŒ€ν•  수 도 μžˆλ‹€.
  • λͺ…λͺ… νŒ¨ν„΄μ—λŠ” νŒ¨ν„΄ 싀행에 ν•„μš”ν•œ 인자λ₯Ό λ§€κ°œλ³€μˆ˜λ‘œ λ„˜κΈΈ 방법이 λ§ˆλ•…μΉ˜ μ•Šλ‹€.

-> λͺ…λͺ… νŒ¨ν„΄ λŒ€μ‹  μ—λ„ˆν…Œμ΄μ…˜μ„ μ“°μž !




μ—λ„ˆν…Œμ΄μ…˜ μ‚¬μš©ν•˜κΈ°

μ—λ„ˆν…Œμ΄μ…˜ μ„Έκ°œλ₯Ό λ§Œλ“€μ–΄ λ³΄λ©΄μ„œ, μ—λ„ˆν…Œμ΄μ…˜μ΄ 무엇인지와 λͺ…λͺ…νŒ¨ν„΄μ˜ 단점을 μ–΄λ–»κ²Œ 보완 ν•˜λŠ”μ§€ μ•Œμ•„λ³΄μž !


λͺ©ν‘œ : λ§€κ°œλ³€μˆ˜ μ—†λŠ” 정적 λ©”μ„œλ“œμ—λ§Œ μ“Έ 수 μžˆλŠ” ν…ŒμŠ€νŠΈ μ—λ„ˆν…Œμ΄μ…˜μ„ λ§Œλ“€μ–΄λ³΄μž ! - Annotation Processor λ₯Ό μ‚¬μš©ν•΄λ³΄μž.


0. μƒˆλ‘œμš΄ ν”„λ‘œμ νŠΈ λ§Œλ“€κΈ°

  • μƒˆλ‘œμš΄ ν”„λ‘œμ νŠΈλ₯Ό λ§Œλ“€κ³ , μ μ ˆν•œ groupId와 article 을 μ§€μ •ν•œλ‹€.
  • κΈ°λ³Έ μƒμ„±λ˜λŠ” μŠ€ν”„λ§μ˜ Application ν΄λž˜μŠ€μ™€ ν…ŒμŠ€νŠΈ ν΄λž˜μŠ€λ“€μ„ μ‚­μ œν•œλ‹€. (선택)

ν”„λ‘œμ  λ§Œλ“€κΈ°


1. μ—λ„ˆν…Œμ΄μ…˜ λ§Œλ“€κΈ°

/**
 * 이 μ—λ„ˆν…Œμ΄μ…˜μ€ λ§€κ°œλ³€μˆ˜ μ—†λŠ” 정적 λ©”μ„œλ“œμ—λ§Œ 달 수 μžˆλŠ” 마컀 μ—λ„ˆν…Œμ΄μ…˜μ΄λ‹€.
 */
@Retention(RetentionPolicy.SOURCE) // 컴파일 ν›„ μ—λ„ˆν…Œμ΄μ…˜ 정보 사라짐
@Target(ElementType.METHOD) // λ©”μ„œλ“œμ—λ§Œ 달 수 있음
public @interface CustomTest {
}
  • 메타 μ—λ„ˆν…Œμ΄μ…˜ : μ—λ„ˆν…Œμ΄μ…˜μ„ λ§Œλ“€λ•Œ λΆ™μ΄λŠ” μ—λ„ˆν…Œμ΄μ…˜
    • @Retention : 인자둜 μ—λ„ˆν…Œμ΄μ…˜ 정보가 μ–Έμ œκΉŒμ§€ λ‚¨μ•„μžˆμ„μ§€ μ§€μ •ν•œλ‹€.
    • @Target : 인자둜 ν•΄λ‹Ή μ—λ„ˆν…Œμ΄μ…˜μ΄ 어디에 λΆ™μ–΄μžˆμ„ 수 μžˆλŠ”μ§€ μ§€μ •ν•œλ‹€.
  • 마컀 μ—λ„ˆν…Œμ΄μ…˜ : 아무 λ§€κ°œλ³€μˆ˜ 없이 λ‹¨μˆœνžˆ λ§ˆν‚Ήμ— μ‚¬μš©ν•˜λŠ” μ—λ„ˆν…Œμ΄μ…˜ (ex. @Override)

2. μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ μž‘μ„±

  • μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œλŠ” μ—λ„ˆν…Œμ΄μ…˜μ„ 읽고 μ½”λ“œλ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ νŠΉμ • μž‘μ—…μ„ ν•  수 있게 ν•΄μ€€λ‹€.
  • μ—λ„ˆν…Œμ΄μ…˜μ€ 기본적으둜 λ¦¬ν”Œλ ‰μ…˜μ„ μ΄μš©ν•˜μ—¬ λ™μž‘ν•œλ‹€.
@SupportedAnnotationTypes("com.meetcoder.testannotation.CustomTest")

public class CustomTestProcessor extends AbstractProcessor {

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(CustomTest.class);
        for(Element element : elementsAnnotatedWith){
            makeErrorIfNotStaticMethod(element);
        }
        return true;
    }
    
    private void makeErrorIfNotStaticMethod(Element element) {
        if (isNotStaticMethod(element)) {
            processingEnv.getMessager().printMessage(Kind.ERROR, "static λ©”μ„œλ“œκ°€ μ•„λ‹™λ‹ˆλ‹€.");
        }
    }
    
    private boolean isNotStaticMethod(Element element) {
        return !element.getModifiers().contains(Modifier.STATIC);
    }
}

3. compile

mvn compile (λΉŒλ“œλ„κ΅¬) 둜 μ»΄νŒŒμΌν•œλ‹€.


4. resources/META-INF/services/javax.annotation.processing.Processor 파일 λ§Œλ“€κΈ°

  • μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œλ₯Ό μ΄μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 정해진 μœ„μΉ˜μ— 등둝해야 ν•œλ‹€.
  • μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œλ₯Ό μ“°κΈ° μœ„ν•΄μ„œλŠ” λ‹€μŒ 경둜λ₯Ό λ§Œλ“€κ³ , javax~ νŒŒμΌμ„ λ§Œλ“€μ–΄μ•Ό ν•œλ‹€.
  • 이 파일 μ•ˆμ— μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œμ˜ FQCN 을 μž‘μ„±ν•œλ‹€.

등둝
(각자의 μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ κ²½λ‘œμ— 맞게 μž‘μ„±ν•˜κΈ° ! )


5. mvn install (λΉŒλ“œλ„κ΅¬) 둜 jar 파일 λ§Œλ“€κΈ°

  • pom.xml 에 ν•„μš”μ—†λŠ” μ˜μ‘΄μ„±κ³Ό ν”ŒλŸ¬κ·ΈμΈμ„ μ‚­μ œν›„ jar 파일둜 λ§Œλ“ λ‹€.

νŒ¨ν‚€μ§€ ꡬ쑰
(μ—λ„ˆν…Œμ΄μ…˜ ν•˜λ‚˜, μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ ν•˜λ‚˜, λ“±λ‘ν•˜λŠ” λ¦¬μ†ŒμŠ€νŒŒμΌ ν•˜λ‚˜)


6. μ—λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•  ν”„λ‘œμ νŠΈμ—μ„œ μ˜μ‘΄μ„± μΆ”κ°€

μ˜μ‘΄μ„± (방금 λ§Œλ“  jar λ₯Ό κ°€μ Έμ˜€κΈ° μœ„ν•΄ μ˜μ‘΄μ„± μΆ”)


7. μ—λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•œ ν›„, 컴파일만 ν•΄μ„œ 였λ₯˜κ°€ λœ¨λŠ”μ§€ 확인

ν…ŒμŠ€νŠΈ (static 이 μ•„λ‹Œ λ©”μ„œλ“œμ— μ—λ„ˆν…Œμ΄μ…˜ λΆ™μ˜€μ„ μ‹œ, λŸ°νƒ€μž„μ΄ μ•„λ‹Œ μ»΄νŒŒμΌνƒ€μž„μ— μ—λŸ¬κ°€ λœ¬λ‹€.)






λ§€κ°œκ°’μ΄ μžˆλŠ” μ—λ„ˆν…Œμ΄μ…˜

λͺ©ν‘œ : μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ μ„±κ³΅ν•˜λŠ” ν…ŒμŠ€νŠΈ μ—λ„ˆν…Œμ΄μ…˜μ„ λ§Œλ“€μ–΄ 보자 ! 이 μ—λ„ˆν…Œμ΄μ…˜μ€ μΈμžκ°’μœΌλ‘œ μ—λŸ¬λ₯Ό μ§€μ •ν•˜κ³ , 반볡 μ‚¬μš©μœΌλ‘œ μ—¬λŸ¬ μ—λŸ¬λ₯Ό 지정할 수 μžˆμ–΄μ•Ό ν•œλ‹€.


μ΄λ²ˆμ—λŠ” λ©”μΈλ©”μ„œλ“œμ— ν…ŒμŠ€νŠΈ λŸ¬λ„ˆλ₯Ό μž‘μ„±ν•  것이닀. (μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œ λ§Œλ“€κΈ°μ— μ‹€νŒ¨ν–ˆμŠ΅λ‹ˆλ‹€....) μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œμ˜ μž₯점은 μ»΄νŒŒμΌνƒ€μž„μ— 였λ₯˜λ₯Ό μž‘μ„ 수 μžˆλ‹€λŠ” 것이닀, ν…ŒμŠ€νŠΈ λŸ¬λ„ˆλ₯Ό λ§Œλ“€μ–΄μ„œ ν•˜λ©΄ λŸ°νƒ€μž„μ— 였λ₯˜λ₯Ό 확인할 수 μžˆλ‹€.



1. μ—λ„ˆν…Œμ΄μ…˜ 생성

@Repeatable(ExceptionTestContainer.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
    Class<? extends Throwable> value();
}
  • value() λΌλŠ” μ΄λ¦„μœΌλ‘œ μ§€μ •ν•˜λ©΄ μ—λ„ˆν…Œμ΄μ…˜ μ‚¬μš©μ‹œ νƒ€μž…μ„ μ§€μ •ν•˜μ§€ μ•Šμ•„λ„ 됨.
  • 같은 μ—λ„ˆν…Œμ΄μ…˜μ„ μ—¬λŸ¬κ°œ 달기 μœ„ν•΄ @Repeatable() 메타 μ—λ„ˆν…Œμ΄μ…˜ μ‚¬μš©
  • @Repeatable 을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ»¨ν…Œμ΄λ„ˆ ν΄λž˜μŠ€κ°€ ν•„μš”ν•˜λ‹€.
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer {
    ExceptionTest[] value();
}

2. ν…ŒμŠ€νŠΈ λŸ¬λ„ˆ μž‘μ„±

public class RunTest {

    private Class<?> testClass;
    private int tests = 0;
    private int passed = 0;

    public RunTest(String path) {
        try {
            this.testClass = Class.forName(path);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public Class<?> getTestClass() {
        return testClass;
    }

    public void run(Class<?> runTest) {
        for (Method method : runTest.getDeclaredMethods()) {
            if (method.isAnnotationPresent(ExceptionTest.class) || method.isAnnotationPresent(ExceptionTestContainer.class)) {
                tests++;

                try {
                    method.invoke(null);
                    System.err.printf("**ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨ : μ˜ˆμ™Έλ₯Ό λ˜μ§€μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€ !**%n", method.getName());
                } catch (Throwable wrappedExc) {
                    Throwable exc = wrappedExc.getCause();
                    int oldPassed = passed;
                    ExceptionTest[] exceptionTests = method.getAnnotationsByType(ExceptionTest.class);

                    for (ExceptionTest exceptionTest : exceptionTests) {
                        if (exceptionTest.value().isInstance(exc)) {
                            passed++;
                            System.out.printf("**ν…ŒμŠ€νŠΈ %s μ—μ„œ μ˜ˆμƒλŒ€λ‘œ %s μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€ !**%n", method.getName(), exc.getClass());
                            break;
                        }
                    }

                    if (passed == oldPassed) {
                        System.err.printf("**ν…ŒμŠ€νŠΈ %s μ‹€νŒ¨ : λ‹€λ₯Έ μ˜ˆμ™Έ %s κ°€ λ°œμƒν•˜μ˜€μŠ΅λ‹ˆλ‹€ !**%n", method.getName(), exc.getClass());
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws ClassNotFoundException {

        RunTest runTest = new RunTest("Chapter6.Day39.ExceptionTest.Tests");
        Class<?> testClass = runTest.getTestClass();
        runTest.run(testClass);
    }
}

@Repeatable μ—λ„ˆν…Œμ΄μ…˜μ΄ λΆ™μ–΄ μ—λ„ˆν…Œμ΄μ…˜μ„ μ—¬λŸ¬λ²ˆ 썼닀면, λ‚΄λΆ€μ μœΌλ‘œ μ»¨ν…Œμ΄λ„ˆ μ—λ„ˆν…Œμ΄μ…˜μœΌλ‘œ μ μš©ν•œλ‹€. ν•œλ²ˆ μ“΄ μ—λ„ˆν…Œμ΄μ…˜κ³Ό κ΅¬λΆ„ν•˜κΈ° μœ„ν•¨μ΄λ‹€.

  • AnnotatedElement.getAnnotationsByType() : μ›λž˜ μ—λ„ˆν…Œμ΄μ…˜κ³Ό μ»¨ν…Œμ΄λ„ˆ μ—λ„ˆν…Œμ΄μ…˜μ„ κ΅¬λΆ„ν•˜μ§€ μ•ŠμŒ. λ”°λΌμ„œ 두 경우 λͺ¨λ‘ κ°€μ Έμ˜΄.
  • AnnotatedElement.isAnnotationPresent() : μ›λž˜ μ—λ„ˆν…Œμ΄μ…˜κ³Ό μ»¨ν…Œμ΄λ„ˆ μ—λ„ˆν…Œμ΄μ…˜μ„ ꡬ뢄함. λ”°λΌμ„œ μ›λž˜ μ—λ„ˆν…Œμ΄μ…˜μ„ 이 λ©”μ„œλ“œλ‘œ κ²€μ‚¬ν•œλ‹€λ©΄ [μ•„λ‹ˆλ‹€] 라고 ν•  것이닀.

λ”°λΌμ„œ getAnnotationsByType() 으둜 κ²€μ‚¬ν•œλ‹€.


κ²°κ³Ό



κ²°λ‘ 

  • λͺ…λͺ…νŒ¨ν„΄ 단점 1 : μ˜€νƒ€λ‚˜λ©΄ 인식λͺ»ν•¨
    • μ—λ„ˆν…Œμ΄μ…˜μ€ μ˜€νƒ€λ‚˜λ©΄ 컴파일쑰차 μ•ˆλœλ‹€.
  • λͺ…λͺ…νŒ¨ν„΄ 단점 2 : μ΄μƒν•œ 데에 μ“Έ μˆ˜λ„ 있음
    • @Target, λ˜λŠ” μ—λ„ˆν…Œμ΄μ…˜ ν”„λ‘œμ„Έμ„œμ—μ„œμ˜ 검사λ₯Ό 톡해 μ œν•œκ°€λŠ₯
  • λͺ…λͺ…νŒ¨ν„΄ 단점 3 : 싀행에 ν•„μš”ν•œ μš”μ†Œ 전달이 λΆˆκ°€
    • μ—λ„ˆν…Œμ΄μ…˜μ— λ§€κ°œλ³€μˆ˜λ‘œ 전달 κ°€λŠ₯

μ—λ„ˆν…Œμ΄μ…˜ μ“°μž.