2011-10-03 4 views
10

나는 JUnit 테스트 클래스의 JUnit 모음 인 클래스를 가지고있다. 나는 suite에 정의하여 각 단위 테스트가 실행되기 전후에 데이터베이스에 어떤 작업을 수행하고자 할 때 해당 테스트 메소드에 특정 주석이있는 경우 실행하려고합니다.테스트 스위트에서 JUnit 메소드 규칙을 정의하는 방법은 무엇입니까?

나는 각 클래스 (전에는 충분하지 않음) 전에 이것을 수행 할 스위트와 테스트 클래스에서 @ClassRule을 만들 수 있었으며 테스트 규칙을 정의 할 수있었습니다. 테스트 클래스 자체는 반복적 인 것으로 매우 건조하지는 않습니다.

스위트에서 테스트 메소드마다 규칙을 정의 할 수 있습니까? 아니면 각 테스트에 추가해야합니까?

편집 : 명확하게하기 위해 테스트 클래스의 테스트 메소드간에 실행되는 코드를 스위트에 선언하고 싶습니다.

답변

11

이 작업은 수행 할 수 있지만 약간의 작업이 필요합니다. 자신의 Suite 러너와 자신의 테스트 러너를 정의한 다음 테스트 러너에서 runChild()를 재정의해야합니다. 다음과 스위트 룸 및 테스트 클래스를 사용 : 나는 @Deprecatedtest1()을 주석 한

@RunWith(MySuite.class) 
@SuiteClasses({Class1Test.class}) 
public class AllTests { 
} 

public class Class1Test { 
    @Deprecated @Test public void test1() { 
     System.out.println("" + this.getClass().getName() + " test1"); 
    } 

    @Test public void test2() { 
     System.out.println("" + this.getClass().getName() + " test2"); 
    } 
} 

참고. 당신은 당신이 시험에 @Deprecated 주석이있을 때 뭔가 다른 일을하고 싶은, 그래서 우리는 사용자 정의 Runner 사용하는 스위트 룸을 확장해야합니다

public class MySuite extends Suite { 
    // copied from Suite 
    private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws InitializationError { 
     Suite.SuiteClasses annotation = klass.getAnnotation(Suite.SuiteClasses.class); 
     if (annotation == null) { 
      throw new InitializationError(String.format("class '%s' must have a SuiteClasses annotation", klass.getName())); 
     } 
     return annotation.value(); 
    } 

    // copied from Suite 
    public MySuite(Class<?> klass, RunnerBuilder builder) throws InitializationError { 
     super(null, getRunners(getAnnotatedClasses(klass))); 
    } 

    public static List<Runner> getRunners(Class<?>[] classes) throws InitializationError { 
     List<Runner> runners = new LinkedList<Runner>(); 

     for (Class<?> klazz : classes) { 
      runners.add(new MyRunner(klazz)); 
     } 

     return runners; 
    } 
} 

의 JUnit 그것을 실행할 각 시험에 대한 Runner 만듭니다. 일반적으로 Suite는 기본값 BlockJUnit4ClassRunner을 만들 것입니다. 여기서 우리가하는 것은 SuiteClass 주석에서 클래스를 읽는 Suite의 생성자를 재정의하는 것입니다. 그리고 우리는 자신의 주자를 MyRunner으로 만듭니다. 이것은 MyRunner 클래스입니다.

public class MyRunner extends BlockJUnit4ClassRunner { 
    public MyRunner(Class<?> klass) throws InitializationError { 
     super(klass); 
    } 

    @Override 
    protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 
     Description description= describeChild(method); 
     if (method.getAnnotation(Ignore.class) != null) { 
      notifier.fireTestIgnored(description); 
     } else { 
      if (description.getAnnotation(Deprecated.class) != null) { 
       System.out.println("name=" + description.getMethodName() + " annotations=" + description.getAnnotations()); 
      } 
      runLeaf(methodBlock(method), description, notifier); 
     } 
    } 
} 

대부분이 BlockJUnit4ClassRunner에서 복사됩니다.내가 추가 한 비트는 다음과 같습니다 우리는 방법에 @Deprecated 주석의 존재 여부를 테스트하고, 뭔가를 할

if (description.getAnnotation(Deprecated.class) != null) { 
    System.out.println("name=" + description.getMethodName() + " annotations=" + description.getAnnotations()); 
} 

그것은이 있다면. 나머지는 독자를위한 운동으로 남아 있습니다. 위의 Suite를 실행하면 다음과 같이 출력됩니다.

name=test1 annotations=[@java.lang.Deprecated(), @org.junit.Test(expected=class org.junit.Test$None, timeout=0)] 
uk.co.farwell.junit.run.Class1Test test1 
uk.co.farwell.junit.run.Class1Test test2 

Suite에는 호출 방법에 따라 여러 생성자가 있습니다. 위의 작업은 Eclipse에서 작동하지만 Suite를 실행하는 다른 방법은 테스트하지 않았습니다. 자세한 내용은 Suite의 다양한 생성자와 함께 주석을 참조하십시오.

-2

TestNG를 사용하면 group tests이 될 수 있습니다. 그리고 일부 로직을 실행하도록 TestNG를 구성 할 수 있습니다 @BeforeGroup and @AfterGroup.

+0

나는 그것이 내가 찾고있는 것이라고 생각하지 않는다. 각 테스트 사이에 무언가가 필요합니다. – ArtB

+0

그러나 테스트 그룹이있는 경우 BeforeMethod 및 AfterMethod를 사용할 수 있어야합니다. (아마도) – ollins

+2

어쨌든, JUnit을 사용해야하고 TestNG는 옵션이 아닙니다. – ArtB

2

스위트에 추가하는 RunListener을 사용할 수 있습니다. 규칙이 할 수있는 모든 것을 제공하지는 않지만 사용 가능한 주석이 있어야하는 설명 클래스를 제공합니다. 적어도, 나는 JUnit이 그것을 이해 한 주석으로 만 필터링한다고 생각하지 않는다.

JUnit 개발자는 방금 here에 RunListener를 추가하는 방법을 설명했습니다.

1

자체적으로 @RunWith(Suite.class)으로 주석 된 클래스에 규칙을 추가하면 트릭을 수행하지 않습니다. 나는 이것이 실행되는 클래스에 대한 규칙을 다듬 으려고 시도 할 BlockJUnit4ClassRunner과 같은 Runner이 아닌 SuiteParentRunner<Runner>이기 때문이라고 생각합니다. 자녀를 실행하기 위해 자식 Runners이 실행되도록 지시합니다. 그 Runner s는 해당 클래스에 규칙을 적용하여 테스트를 구축했을 수 있지만 Suite 러너는 자식 Runner 빌드 테스트에 자체 규칙을 적용하는 데 특별한 조치를 취하지 않습니다.

+0

그래서 현재 방법이 없습니다? 말이된다. 나는 그것이 개별적인 테스트가 실패 할 상황에 대해 궁금해했다. 또한 스위트 룸은 단위 테스트를 실행하고 그 라이프 사이클을 후킹 할 수는 없지만 여전히 그 주위를 둘러 볼 수는 없습니다. – ArtB

+0

@ Yishai의 제안을 시도해 보겠습니다. – pholser

0

"테스트 클래스 계층 구조"를 사용해 보셨습니까? 종종 추상적 인 테스트 클래스를 사용하여 테스트 또는 조명을 공유합니다. 예를 들어, 모든 DB 테스트가 내장 된 데이터 소스를 초기화하고 있습니다. 먼저 init 논리를 처리하는 추상 "DbTestCase"클래스를 만듭니다. 그러면 모든 하위 클래스가 테스트 및 조명기에 도움이됩니다.

그러나 테스트 케이스에 단일 계층 구조에 저장할 수없는 많은 테스트/픽스처 로직이 필요한 경우 가끔 문제가 발생합니다. 이 경우 aspect 프로그래밍만으로 문제를 해결할 수 있습니다. 모든 필수 클래스가 구현할 수있는 특정 주석/인터페이스를 통해 테스트/픽스처 로직을 표시합니다.

테스트 된 클래스의 주석/인터페이스에 따라 테스트/픽스처 로직을 "주입"하는 사용자 정의 러너를 사용하여 "애스펙트"처리 옵션을 고려할 수 있습니다.

+0

계층 구조 아이디어는 건전하지만 측면은 흑 마법이나 와사비와 같습니다. 그들은 조심스럽게 사용되어야하며 조심스럽게 사용해야합니다. – ArtB

관련 문제