jUnit 4.x의 Before and After Suite 실행 후크


84

테스트를 실행하기 위해 jUnit 4.4를 사용하여 통합 테스트 세트에 대한 설정 및 분해를 수행하려고합니다. 분해는 안정적으로 실행되어야합니다. TestNG에 다른 문제가 있으므로 jUnit으로 다시 포팅하려고합니다. 테스트가 실행되기 전과 모든 테스트가 완료된 후에 실행할 수있는 후크는 무엇입니까?

참고 : 우리는 빌드에 maven 2를 사용하고 있습니다. 나는 maven의 pre-& post-integration-test단계를 사용해 보았지만 테스트가 실패하면 maven이 중지되고 실행 post-integration-test되지 않으므로 도움이되지 않습니다.


1
통합 테스트 의 경우 surefire 대신 maven-failsafe-plugin을 사용해야합니다 . post-integration-test테스트가 실패 해도 건너 뛰지 않습니다. 참조 이 위키 페이지를 .
Chris H.

최종 구현을 공유해 주시겠습니까?
vikramvi

답변:


113

예, 테스트 스위트에서 테스트 전후에 설정 및 해체 메소드를 안정적으로 실행할 수 있습니다. 코드로 보여 드리겠습니다.

package com.test;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {

    @BeforeClass
    public static void setUp() {
        System.out.println("setting up");
    }

    @AfterClass
    public static void tearDown() {
        System.out.println("tearing down");
    }

}

따라서 Test1수업은 다음과 같습니다.

package com.test;

import org.junit.Test;


public class Test1 {
    @Test
    public void test1() {
        System.out.println("test1");
    }

}

... 그리고 Test2비슷해 보이는 것을 상상할 수 있습니다 . 를 실행 TestSuite하면 다음을 얻을 수 있습니다.

setting up
test1
test2
tearing down

따라서 설정 / 해체가 각각 모든 테스트 전후에만 실행되는 것을 볼 수 있습니다.

캐치 : 이것은 테스트 스위트를 실행하고 개별 JUnit 테스트로 Test1 및 Test2를 실행하지 않는 경우에만 작동합니다. 당신이 maven을 사용하고 있다고 언급했고 maven surefire 플러그인은 스위트의 일부가 아닌 개별적으로 테스트를 실행하는 것을 좋아합니다. 이 경우 각 테스트 클래스가 확장하는 수퍼 클래스를 만드는 것이 좋습니다. 그런 다음 수퍼 클래스에는 주석이 달린 @BeforeClass 및 @AfterClass 메서드가 포함됩니다. 위의 방법만큼 깨끗하지는 않지만 당신에게 효과적이라고 생각합니다.

실패한 테스트의 문제는 maven.test.error.ignore를 설정하여 실패한 테스트에서 빌드가 계속되도록 할 수 있습니다. 이것은 지속적인 연습으로 권장되지는 않지만 모든 테스트를 통과 할 때까지 기능을 발휘해야합니다. 자세한 내용은 maven surefire 문서를 참조하세요 .


2
maven-surefire-plugin에 들어가서 실행하고 싶은 스위트를 가리키는 포함 목록을 만들었을 때 이것은 완벽하게 작동했습니다.
Jherico

2
JUnit 4.8.2부터 이것은 매개 변수화 된 테스트에서 잘 작동하지 않습니다. Suite의 @BeforeClass 메서드는 테스트의 @ Parameterized.Parameters 메서드 이후 에 실행 되어 Suite 설정에 대한 종속성을 방지합니다.
Anm 2011

@Theories를 사용할 때 자신에 대한 응답으로는 @DataPoints 메서드 호출은 호출입니다 이후 스위트의 @BeforeClass.
Anm 2011

18
necro 죄송합니다. 그러나 BeforeClass / AfterClass를 수퍼 클래스에 추가하는 것은 예상대로 작동하지 않습니다. 각 테스트 클래스가 완료된 후에도 여전히 호출됩니다. 이것은 후손을위한 것입니다.
Subu Sankara Subramanian 2012

3
이것이 여전히 유효한 접근 방식입니까? SuiteClasses 주석에서 테스트 클래스 목록을 열거 할 필요를 피하려면 어떻게해야합니까?
Burhan Ali

33

내 동료는 다음을 제안했습니다. 사용자 정의 RunListener를 사용하고 testRunFinished () 메서드를 구현할 수 있습니다. http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html#testRunFinished(org. junit.runner.Result)

RunListener를 등록하려면 다음과 같이 surefire 플러그인을 구성하십시오. http://maven.apache.org/surefire/maven-surefire-plugin/examples/junit.html 섹션 "사용자 정의 리스너 및 리포터 사용"

이 구성은 failsafe 플러그인에서도 선택해야합니다. 이 솔루션은 스위트, 룩업 테스트 클래스 또는 이와 같은 것들을 지정할 필요가 없기 때문에 훌륭합니다. Maven이 모든 테스트가 끝날 때까지 기다릴 수 있도록합니다.


5
+1 스위트 클래스의 번거로운 유지 관리없이 제가 본 첫 번째 사용 가능한 솔루션입니다!
Stefan Haberl 2013-06-24


7

주석을 사용하면 다음과 같이 할 수 있습니다.

import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;

class SomethingUnitTest {
    @BeforeClass
    public static void runBeforeClass()
    {

    }

    @AfterClass
    public static void runAfterClass()
    {  

    }

    @Before  
    public void setUp()
    {

    }

    @After
    public void tearDown()
    {

    }

    @Test
    public void testSomethingOrOther()
    {

    }

}

4
설정 및 분해는 실행 당 한 번 실행해야합니다. 이것은 모든 테스트가 한 클래스에있는 경우에만 도움이됩니다.
sblundy

3

여기, 우리

  • JUnit 4.5로 업그레이드,
  • 작업 서비스가 필요한 각 테스트 클래스 또는 메서드에 태그를 지정하는 주석을 작성했습니다.
  • 서비스의 설정 및 해체를 구현하는 정적 메서드가 포함 된 각 주석에 대한 핸들러를 작성했습니다.
  • 테스트에서 주석을 찾기 위해 일반적인 Runner를 확장하여 적절한 지점의 테스트 실행 체인에 정적 핸들러 메서드를 추가했습니다.

2

"참고 : 우리는 빌드에 maven 2를 사용하고 있습니다. maven의 사전 및 사후 통합 테스트 단계를 사용해 보았지만 테스트가 실패하면 maven이 중지되고 통합 후 테스트를 실행하지 않습니다. , 도움이되지 않습니다. "

대신 failsafe-plugin을 사용해 볼 수 있습니다. 설정 또는 중간 단계 상태에 관계없이 정리가 이루어 지도록 보장하는 기능이 있다고 생각합니다.


예, failsafe 플러그인을 사용하면 특정 설정 및 해체를 지정할 수 있습니다. 이 질문이 게시되었을 때 안전 장치가 존재하지 않았다고 생각합니다.
Jason Axelson 2012

2

모든 테스트가 "기술"클래스를 확장하고 동일한 패키지에있는 경우 약간의 트릭을 수행 할 수 있습니다.

public class AbstractTest {
  private static int nbTests = listClassesIn(<package>).size();
  private static int curTest = 0;

  @BeforeClass
  public static void incCurTest() { curTest++; }

  @AfterClass
  public static void closeTestSuite() {
      if (curTest == nbTests) { /*cleaning*/ }             
  }
}

public class Test1 extends AbstractTest {
   @Test
   public void check() {}
}
public class Test2 extends AbstractTest {
   @Test
   public void check() {}
}

이 솔루션에는 많은 단점이 있습니다.

  • 패키지의 모든 테스트를 실행해야합니다.
  • "기술"클래스를 하위 클래스로 분류해야합니다.
  • @BeforeClass 및 @AfterClass를 하위 클래스 내에서 사용할 수 없습니다.
  • 패키지에서 하나의 테스트 만 실행하면 청소가되지 않습니다.
  • ...

정보 : listClassesIn () => Java에서 주어진 클래스의 모든 하위 클래스를 어떻게 찾습니까?


1
이것은 내 자신의 테스트가 보여주는 한 사실이 아닙니다. 나는 beforeclass에 내장 된 glassfish를 시작하고 수업 후에 종료하는 슈퍼 클래스가 있습니다. 그런 다음 해당 수퍼 클래스에서 확장되는 2 개의 클래스가 있습니다. beforeclass는 각 클래스에 정의 된 테스트를 실행하기 전에 실행됩니다.
Jonathan Morales Vélez

0

내가 아는 한 JUnit에서이 작업을 수행하는 메커니즘은 없지만 Suite 하위 클래스를 만들고 후크를 제공하는 버전으로 run () 메서드를 재정의 할 수 있습니다.


0

maven-surefire-plugin은 Suite 클래스를 먼저 실행하지 않고 Suite 클래스와 테스트 클래스를 동일하게 취급하므로 다음과 같이 플러그인을 구성하여 Suite 클래스 만 활성화하고 모든 테스트를 비활성화 할 수 있습니다. Suite는 모든 테스트를 실행합니다.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.5</version>
            <configuration>
                <includes>
                    <include>**/*Suite.java</include>
                </includes>
                <excludes>
                    <exclude>**/*Test.java</exclude>
                    <exclude>**/*Tests.java</exclude>
                </excludes>
            </configuration>
        </plugin>

0

원하는 기능을 얻는 유일한 방법은 다음과 같은 작업을 수행하는 것입니다.

import junit.framework.Test;  
import junit.framework.TestResult;  
import junit.framework.TestSuite;  

public class AllTests {  
    public static Test suite() {  
        TestSuite suite = new TestSuite("TestEverything");  
        //$JUnit-BEGIN$  
        suite.addTestSuite(TestOne.class);  
        suite.addTestSuite(TestTwo.class);  
        suite.addTestSuite(TestThree.class);  
        //$JUnit-END$  
     }  

     public static void main(String[] args)  
     {  
        AllTests test = new AllTests();  
        Test testCase = test.suite();  
        TestResult result = new TestResult();  
        setUp();  
        testCase.run(result);  
        tearDown();  
     }  
     public void setUp() {}  
     public void tearDown() {}  
} 

나는 이클립스에서 이와 같은 것을 사용하므로 그 환경 밖에서 얼마나 이식 가능한지 잘 모르겠습니다.


3
이것은 JUnit3의 예이며 OP는 JUnit4를 요청했지만 일부 JUnit3 사용자가이 질문을 발견하는 경우를 대비하여 ... JUnit3의 경우 main () 메서드를 제거하고 suite () 메서드를 사용하는 것이 좋습니다. junit.extensions.TestSetup의 하위 클래스에 TestSuite를 래핑합니다. IDE에서 개별 테스트 클래스를 실행하는 것에 대한 Julie의 예제와 동일한주의 사항이 있습니다.
NamshubWriter 2010

0

스위트를 만들고 싶지 않고 모든 테스트 클래스를 나열해야하는 경우 리플렉션을 사용하여 테스트 클래스의 수를 동적으로 찾고 기본 클래스 @AfterClass에서 카운트 다운하여 tearDown을 한 번만 수행 할 수 있습니다.

public class BaseTestClass
{
    private static int testClassToRun = 0;

    // Counting the classes to run so that we can do the tear down only once
    static {
        try {
            Field field = ClassLoader.class.getDeclaredField("classes");
            field.setAccessible(true);

            @SuppressWarnings({ "unchecked", "rawtypes" })
            Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
            for (Class<?> clazz : classes) {
                if (clazz.getName().endsWith("Test")) {
                    testClassToRun++;
                }
            }
        } catch (Exception ignore) {
        }
    }

    // Setup that needs to be done only once
    static {
        // one time set up
    }

    @AfterClass
    public static void baseTearDown() throws Exception
    {
        if (--testClassToRun == 0) {
            // one time clean up
        }
    }
}

정적 블록 대신 @BeforeClass를 사용하는 것을 선호하는 경우 부울 플래그를 사용하여 반사 카운트를 수행하고 첫 번째 호출에서 한 번만 설정을 테스트 할 수도 있습니다. 이것이 누군가에게 도움이되기를 바랍니다. 스위트의 모든 수업을 열거하는 것보다 더 나은 방법을 찾는 데 오후가 걸렸습니다.

이제 모든 테스트 클래스에 대해이 클래스를 확장하기 만하면됩니다. 우리는 이미 모든 테스트에 대해 몇 가지 공통 사항을 제공하는 기본 클래스가 있으므로 이것이 우리에게 최고의 솔루션이었습니다.

영감은이 SO 답변에서 비롯됩니다 https://stackoverflow.com/a/37488620/5930242

이 클래스를 모든 곳으로 확장하고 싶지 않다면 마지막 SO 답변이 원하는 것을 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.