JUnit4에서 특정 순서로 테스트 메소드를 실행하는 방법은 무엇입니까?


413

@Test특정 순서 로 주석이 달린 테스트 방법을 실행하고 싶습니다 .

예를 들면 다음과 같습니다.

public class MyTest {
    @Test public void test1(){}
    @Test public void test2(){}
}

나는 실행할 수 있도록하려는 test1()전에 test2()내가 실행할 때마다 MyTest,하지만 난 같은 주석을 찾을 수 없습니다 @Test(order=xx).

JUnit의 작성자가 주문 기능을 원하지 않는다면 왜 JUnit에 대해 매우 중요한 기능이라고 생각 합니까?


2
그들은 소스 파일에 나타나는 순서대로 실행되는 것 같습니다.
Lorne의 후작

84
지정된 순서로 실행해야하는 테스트를 작성해서는 안됩니다. 정말 나쁜 연습입니다. 모든 테스트는 독립적으로 실행될 수 있어야합니다.
Apfelsaft

5
@EJP 이것은 java pre 7과 거의 보편적으로 맞았습니다. Pre 7, Pre 7 대부분의 JVM이이 작업을 수행했지만 보장되지는 않았습니다. Java 7 JVM은 비 결정적 순서로 메소드를 리턴 할 수 있습니다.
Matthew Farwell

17
해결하십시오. 테스트 케이스에서 @Test를 제거하고 개인 함수로 변환 한 다음 단일 테스트 케이스를 작성하고 개인 함수를 순서대로 호출하십시오.
Simon Guo 2014

12
테스트 케이스에서 @Test를 제거하면 JUnit 보고서가 엉망이됩니다. 그건 그렇고, 특정 주문을 시행하는 것은 단위 테스트에 대한 나쁜 습관 이지만 통합 테스트에 대한 나쁜 습관은 아닙니다 . 최선의 선택은 (안 이상)을 가지는 클래스를 주석하는 것입니다 @FixMethodOrder(MethodSorters.NAME_ASCENDING)의 유지 @Test, 예를 들어, 모든 시험 방법에 대한 주석 및 실행의 원하는 순서에 따라 알파벳순으로 이름을 변경 t1_firstTest(), t2_secondTest()
MisterStrickland

답변:


238

JUnit 작성자가 주문 기능을 원하지 않으면 JUnit에 대해 매우 중요한 기능이라고 생각합니다. 왜 그렇습니까?

JUnit을 사용 하여이 작업을 수행하는 명확한 방법이 있는지 확실하지 않습니다 .JUnit은 모든 테스트를 임의의 순서로 수행 할 수 있다고 가정합니다. FAQ에서 :

테스트 픽스처는 어떻게 사용합니까?

(...) 테스트 메소드 호출 순서가 보장되지 않으므로 testOneItemCollection ()이 testEmptyCollection () 전에 실행될 수 있습니다. (...)

왜 그래야만하지? 글쎄, 나는 테스트 순서에 의존 하는 것이 저자들이 홍보하고 싶지 않은 관행 이라고 믿는다 . 시험은 독립적이어야한다, 그들은 결합해서는 안되며이 위반 됩니다 유지하기 위해 더 열심히 일을 개별적으로 (분명히) 등의 테스트를 수행 할 수있는 능력을 깰 것이다

즉,이 방향으로 가고 싶다면 TestNG를 사용하는 것이 좋습니다 .TestNG는 기본적으로 임의의 순서로 테스트 메소드를 실행하는 것을 지원하므로 메소드 지정과 같은 것은 메소드 그룹에 따라 다릅니다. Cedric Beust는 testng에서 테스트 실행 순서따라 이를 수행하는 방법을 설명합니다 .


14
두 개의 독립적 인 테스트가 있거나 하나의 테스트 만 있으므로 코딩해야합니다.
Jon Freedman

2
@ JonFreedman, 질문을 이해하면서 테스트가 상호 의존적 인 경우는 아니며 테스트 할 사항이 있고 결과가 순서대로 표시되기를 원합니다.
Jon Bright

174
단위 테스트에 순서를 적용하지 않는 것을 이해할 수는 있지만 JUnit을 사용하여 통합 테스트를 작성할 때 테스트 실행 순서를 지정할 수 있으면 좋을 것입니다. 예를 들어 로그인 테스트를 먼저 실행하십시오.
Brian DiCasa 2016 년

13
@BrianD. login은 아마도 다른 모든 것보다 먼저 실행되어야하는 테스트 대신 "고정"일 것입니다. 필자는 로그인 한 BeforeClass를 작성한 다음 어떤 순서로든 실행할 테스트를 작성합니다.
marcospereira

47
"테스트는 독립적이어야 함 => 테스트는 ORDER와 독립적이어야 함"은 의미가 아닙니다. 학생의 숙제에 대한 자동 채점을 고려하십시오. 먼저 작은 입력과 큰 입력에 대한 솔루션을 테스트하고 싶습니다. 더 작은 입력에 대해 솔루션이 실패하는 경우 (시간 / 메모리 제한) 왜 더 큰 입력에 대해 테스트를 실행해야합니까?
mirelon

96

Junit의 기존 인스턴스를 제거 하고 빌드 경로에서 JUnit 4.11 이상을 다운로드 하면 다음 코드는 이름 순서대로 테스트 메소드를 오름차순으로 정렬하여 실행합니다.

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {

    @Test
    public void testAcreate() {
        System.out.println("first");
    }
    @Test
    public void testBupdate() {
        System.out.println("second");
    }
    @Test
    public void testCdelete() {
        System.out.println("third");
    }
}

8
예를 들어 실제로 비슷한 메소드 test_001_login ()을 시도했지만 대부분 순서를 유지하기 위해 작동하지만 보장되지는 않습니다. 007, 005 및 006이 007 이후에 실행되는 테스트 실행 당 여러 인스턴스가 있습니다. "WTF!"라고 말하고 응답을 위해 StackOverflow로 실행하십시오.
Max P Magee

최고
-JUnit

1
내 테스트에서 : testAcase-작동, test_A_case / testA_case-하지 않았습니다!
Rodislav Moldovan 2016

6
이 주석 매개 변수 "MethodSorters.JVM"을 시도했습니다 (예 : "@FixMethodOrder (MethodSorters.JVM)"). API에서 : JVM-테스트 메소드를 JVM이 리턴 한 순서대로 둡니다. 내가하고있는 일 (CRUD)에 대해서만 잘 작동하고 작성된 순서대로 테스트 방법을 실행합니다. +1
Edvinauskas

1
이 주석은 실제로 대답이지만 주석 (junit 4.12에서)으로 정의되지 않았 @Inherited으므로 AbstractTestCase부모 클래스 에서 효과 가 없다는 경고가 있습니다 .
AbVog

49

주문이 중요한 경우 직접 주문해야합니다.

@Test public void test1() { ... }
@Test public void test2() { test1(); ... }

특히 필요한 경우 테스트 할 순서 순열의 일부 또는 전부를 나열해야합니다.

예를 들어

void test1(); 
void test2(); 
void test3(); 


@Test
public void testOrder1() { test1(); test3(); }

@Test(expected = Exception.class)
public void testOrder2() { test2(); test3(); test1(); }

@Test(expected = NullPointerException.class)
public void testOrder3() { test3(); test1(); test2(); }

또는 모든 순열에 대한 전체 테스트 :

@Test
public void testAllOrders() {
    for (Object[] sample: permute(1, 2, 3)) {
        for (Object index: sample) {
            switch (((Integer) index).intValue()) {
                case 1: test1(); break; 
                case 2: test2(); break; 
                case 3: test3(); break; 
            }
        }
    }
}

여기에 permute()가능한 모든 순열을 배열 컬렉션으로 반복하는 간단한 함수가 있습니다.


그러나 다른 파일에서 테스트하면 어떻게 될까요?
Oleg Abrazhaev

3
첫 번째 코드 블록에서 다시test2 실행 test1 됩니다 . Junit은 여전히 test2이전에 실행될 수 있습니다 test1. 이것은 의도 한 것이 아니며 질문에 대한 올바른 대답이 아닙니다.
toolforger

47

TestNG로 마이그레이션하는 것이 가장 좋은 방법이지만 jUnit에 대한 명확한 해결책은 없습니다. jUnit에 대해 찾은 가장 읽기 쉬운 솔루션 / 형식 은 다음과 같습니다 .

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class SampleTest {
    @Test
    void stage1_prepareAndTest(){};

    @Test
    void stage2_checkSomething(){};

    @Test
    void stage2_checkSomethingElse(){};

    @Test
    void stage3_thisDependsOnStage2(){};

    @Test
    void callTimeDoesntMatter(){}
}

이것은 stage2 메소드가 stage1 메소드 이후와 stage3 메소드 이전에 호출되도록합니다.


5
이 방법은 훌륭하지만 10 개 이상의 테스트가있는 경우 0접두사 를 추가하지 않으면 제대로 작동하지 않습니다 . 예를 들어void stage01_prepareAndTest(){ }
EliuX

10 개 이상의 스테이지가있는 경우 (테스트 아님) -예. 가능한 경우 단계 수를 제한하고 각 단계에서 더 많은 테스트를받는 것을 선호합니다.
joro

18

Junit에서 일할 때 직면 한 주요 문제 중 하나이며 다음과 같은 솔루션을 찾았습니다.

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;

public class OrderedRunner extends BlockJUnit4ClassRunner {

    public OrderedRunner(Class<?> clazz) throws InitializationError {
        super(clazz);
    }

    @Override
    protected List<FrameworkMethod> computeTestMethods() {
        List<FrameworkMethod> list = super.computeTestMethods();
        List<FrameworkMethod> copy = new ArrayList<FrameworkMethod>(list);
        Collections.sort(copy, new Comparator<FrameworkMethod>() {

            @Override
            public int compare(FrameworkMethod f1, FrameworkMethod f2) {
                Order o1 = f1.getAnnotation(Order.class);
                Order o2 = f2.getAnnotation(Order.class);

                if (o1 == null || o2 == null) {
                    return -1;
                }

                return o1.order() - o2.order();
            }
        });
        return copy;
    }
}

또한 아래와 같은 인터페이스를 만듭니다.

 @Retention(RetentionPolicy.RUNTIME)


@Target({ ElementType.METHOD})

public @interface Order {
public int order();
}

다음과 같이 몇 가지 테스트 사례를 작성한 클래스 A가 있다고 가정하십시오.

(@runWith=OrderRunner.class)
Class A{
@Test
@Order(order = 1)

void method(){

//do something

}

}

따라서 "method ()"라는 메소드에서 실행이 시작됩니다. 감사!


PowerMock과 함께 다른 JUnit 러너 사용 버전 1.6.0부터 PowerMock은 JUnit 규칙을 사용하지 않고 테스트 실행을 다른 JUnit 러너에게 위임하는 기능을 지원합니다. 실제 시험 실행은 선택한 다른 러너에게 맡겨집니다. @RunWith(PowerMockRunner.class) @PowerMockRunnerDelegate(OrderedRunner.class)
Kyriakos Georgiopoulos

11

JUnit은 현재 클래스 어노테이션을 사용하여 테스트 메소드 실행 순서를 허용합니다.

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@FixMethodOrder(MethodSorters.JVM)
@FixMethodOrder(MethodSorters.DEFAULT)

기본적으로 테스트 방법은 알파벳 순서로 실행됩니다. 따라서 특정 방법 순서를 설정하려면 다음과 같이 이름을 지정할 수 있습니다.

a_TestWorkUnit_WithCertainState_ShouldDoSomething b_TestWorkUnit_WithCertainState_ShouldDoSomething c_TestWorkUnit_WithCertainState_ShouldDoSomething

여기에서 예제 를 찾을 수 있습니다 .


8

https://github.com/junit-team/junit/pull/386 (아직 출시되지 않은) 변경 사항 은 @SortMethodsWith. https://github.com/junit-team/junit/pull/293 적어도 주문 없이는 주문을 예측 가능하게 만들었습니다 (Java 7에서는 상당히 임의적 일 수 있음).


1
4.386에서 # 386이 병합 된 것 같습니다.
Jesse Glick

이 페이지 아래에 더 언급 된 바와 같이, 실제로 는 4.11에서 호출 @FixMethodOrder되지 않습니다@SortMethodsWith
vorburger

6

JUnit 보고서를보십시오. JUnit은 이미 패키지별로 구성되어 있습니다. 각 패키지는 TestSuite 클래스를 갖거나 가질 수 있으며, 각 클래스는 여러 개의 TestCase를 실행합니다. 각 TestCase는 형식의 여러 테스트 메소드를 가질 수 있으며 public void test*(), 각 메소드 는 실제로 이들이 속하는 TestCase 클래스의 인스턴스가됩니다. 각 테스트 방법 (TestCase 인스턴스)에는 이름과 통과 / 실패 기준이 있습니다.

경영진이 필요로하는 것은 개별 TestStep 항목 의 개념으로 , 각각 고유 한 합격 / 불합격 기준을보고합니다. 테스트 단계가 실패해도 후속 테스트 단계가 실행되지 않아야합니다.

과거에는 테스트 개발자가 테스트중인 제품의 일부에 해당하는 패키지로 TestCase 클래스를 구성하고 각 테스트에 대해 TestCase 클래스를 작성했으며 테스트에서 각 테스트 방법을 별도의 "단계"로 만들었습니다. JUnit 출력에서 ​​자체 통과 / 실패 기준으로 완료하십시오. 각 TestCase는 독립형 "테스트"이지만 TestCase 내의 개별 메소드 또는 테스트 "단계"는 특정 순서로 발생해야합니다.

TestCase 방법은 TestCase의 단계였으며 테스트 디자이너는 테스트 단계마다 별도의 합격 / 불합격 기준을 받았습니다. 이제 테스트 단계가 혼란스럽고 테스트는 물론 실패합니다.

예를 들면 다음과 같습니다.

Class testStateChanges extends TestCase

public void testCreateObjectPlacesTheObjectInStateA()
public void testTransitionToStateBAndValidateStateB()
public void testTransitionToStateCAndValidateStateC()
public void testTryToDeleteObjectinStateCAndValidateObjectStillExists()
public void testTransitionToStateAAndValidateStateA()
public void testDeleteObjectInStateAAndObjectDoesNotExist()
public void cleanupIfAnythingWentWrong()

각 테스트 방법은 자체적 인 합격 / 불합격 기준을 주장하고보고합니다. 주문을 위해이를 "하나의 큰 테스트 방법"으로 축소하면 JUnit 요약 보고서에서 각 "단계"의 합격 / 불합격 기준 세분성이 손실됩니다. ... 내 매니저들을 화나게합니다. 그들은 현재 다른 대안을 요구하고 있습니다.

스크램블 된 테스트 방법 순서를 가진 JUnit이 위에서 예시되고 관리자가 요구하는 각 순차적 테스트 단계의 개별 통과 / 실패 기준을 어떻게 지원하는지 설명 할 수 있습니까?

문서에 관계없이 JUnit 프레임 워크에서 심각한 회귀가 발생하여 많은 테스트 개발자가 어려움을 겪고 있다고 생각합니다.


6

JUnit 5 업데이트 및 내 의견

JUnit 작성자가 주문 기능을 원하지 않으면 JUnit에 대해 매우 중요한 기능이라고 생각합니다. 왜 그렇습니까?

기본적으로 단위 테스트 라이브러리는 소스 파일에서 발생하는 순서대로 테스트를 실행하지 않습니다.
JUnit 4로서의 JUnit 5는 그런 식으로 작동합니다. 왜 ? 순서가 중요하다면 일부 테스트가 서로 결합되어 단위 테스트에 바람직하지 않기 때문 입니다.
따라서 @NestedJUnit 5에서 도입 한 기능은 동일한 기본 접근 방식을 따릅니다.

그러나 통합 테스트의 경우 테스트 방법이 다른 테스트 방법에서 예상 한 방식으로 응용 프로그램의 상태를 변경할 수 있으므로 테스트 방법의 순서가 중요 할 수 있습니다. 예를 들어 e-shop 체크 아웃 처리를위한 통합 테스트를 작성할 때 가장 먼저 실행되는 테스트 방법은 클라이언트를 등록하는 것이고, 두 번째는 바스켓에 항목을 추가하고 마지막은 체크 아웃을 수행하는 것입니다. 테스트 러너가 해당 순서를 준수하지 않으면 테스트 시나리오에 결함이있어 실패합니다.
따라서 JUnit 5 (5.4 버전)에서는 테스트 클래스에 주석을 달고 순서가 중요한 메소드 @TestMethodOrder(OrderAnnotation.class)의 순서를 지정하여 실행 순서를 설정할 수 @Order(numericOrderValue)있습니다.

예를 들면 다음과 같습니다.

@TestMethodOrder(OrderAnnotation.class) 
class FooTest {

    @Order(3)
    @Test
    void checkoutOrder() {
        System.out.println("checkoutOrder");
    }

    @Order(2)
    @Test
    void addItemsInBasket() {
        System.out.println("addItemsInBasket");
    }

    @Order(1)
    @Test
    void createUserAndLogin() {
        System.out.println("createUserAndLogin");
    }
}

출력 :

createUserAndLogin

addItemsInBasket

주문하기

그건 그렇고, 지정 @TestMethodOrder(OrderAnnotation.class)이 필요하지 않은 것처럼 보입니다 (적어도 테스트 한 5.4.0 버전에서는).

참고 사항
질문에 대해 : JUnit 5가 통합 테스트를 작성하는 가장 좋은 선택입니까? 첫 번째로 고려해야 할 도구라고 생각하지는 않지만 (오이와 공동은 통합 테스트를 위해 더 구체적인 가치와 기능을 제공 할 수 있습니다) 일부 통합 테스트 사례에서는 JUnit 프레임 워크로 충분합니다. 이 기능이 존재한다는 것은 좋은 소식입니다.


4

동의하지 않습니다. '파일 업로드'를 테스트 한 다음 '파일 업로드에 의해 삽입 된 데이터'를 테스트하려면 왜 서로 독립적이지 않겠습니까? 완벽하게 합리적 나는 골리앗 테스트 케이스에두기보다는 개별적으로 실행할 수 있다고 생각합니다.


3

테스트 케이스가 스위트로 실행될 때 원하는 것은 완벽합니다.

불행히도 지금은 완벽한 솔루션을 제공 할 시간이 없지만 수업을 살펴보십시오.

org.junit.runners.Suite

특정 순서로 테스트 케이스 (모든 테스트 클래스에서)를 호출 할 수 있습니다.

기능, 통합 또는 시스템 테스트를 작성하는 데 사용될 수 있습니다.

이렇게하면 단위 테스트가 특정 순서없이 (권장대로) 실행되는지 여부에 관계없이 테스트를 그대로두고 더 큰 그림의 일부로 테스트를 재사용 할 수 있습니다.

우리는 단위, 통합 및 시스템 테스트, 때로는 데이터 구동, 때로는 커밋 구동, 때로는 스위트로 실행하기 위해 동일한 코드를 재사용 / 상속합니다.


2
2014 년 이후로이 답변을 완료 할 시간이 없습니까? ;)
Charlie

2

내 솔루션을 참조하십시오 : "Junit and java 7"

이 기사에서는 "소스 코드에서와 같이"순서대로 junit 테스트를 실행하는 방법을 설명합니다. 테스트 메소드가 클래스 파일에 표시되도록 테스트가 실행됩니다.

http://intellijava.blogspot.com/2012/05/junit-and-java-7.html

그러나 파스칼 티 벤트가 말했듯이 이것은 좋은 연습이 아닙니다.


나는 귀하의 블로그 게시물을 보았습니다 (러시아어!). 그러나 이것은 너무 복잡합니다.
Nicolas Barbulesco

1
@NicolasBarbulesco 나는 두 개의 블로그 (rus와 eng)가 있습니다. 실행 순서 의존성으로 테스트를 생성하지 않기 때문에 너무 복잡합니다. 내 솔루션은 해결 방법이지만 실제 솔루션은 해당 종속성을 제거하는 것입니다.
kornero

1
이 게시물에는 실제 답변이 없습니다. 링크 외에 최소한 기본 설명을 추가하십시오.
기본 로케일


0

몇 가지 답변을 읽었으며 모범 사례는 아니지만 테스트를 주문하는 가장 쉬운 방법에 동의합니다. JUnit이 기본적으로 테스트를 실행하는 방법은 알파벳 이름 오름차순입니다.

따라서 원하는 알파벳 순서로 테스트 이름을 지정하십시오. 또한 테스트 이름은 단어 test로 시작해야합니다. 숫자 만 조심하세요

test12는 test2 전에 실행됩니다

그래서:

testA_MyFirstTest 테스트 C_Third 테스트 테스트 B_ATestThatRunsSecond


0

https://github.com/TransparentMarket/junit를 확인 하십시오 . 지정된 순서대로 (컴파일 된 클래스 파일 내에 정의 된) 테스트를 실행합니다. 또한 하위 패키지로 정의 된 테스트를 먼저 실행하는 AllTests 제품군이 있습니다. AllTests 구현을 사용하면 속성을 필터링하여 솔루션을 확장 할 수 있습니다 (우리는 @Fast 주석을 사용했지만 아직 게시되지 않았습니다).


0

다음은 원하는 동작을 생성 할 수있는 JUnit의 확장입니다. https://github.com/aafuks/aaf-junit

나는 이것이 JUnit 철학의 저자에 위배된다는 것을 알고 있지만, 엄격한 단위 테스트 (Java로 실습 된)가 아닌 환경에서 JUnit을 사용하면 매우 도움이 될 수 있습니다.


0

나는 내 테스트가 순서대로 실행되지 않았다고 생각하면서 끝났지 만 진실은 엉망이 내 비동기 작업에 있다는 것입니다. 동시성 작업시 테스트간에 동시성 검사를 수행해야합니다. 필자의 경우 작업과 테스트는 세마포어를 공유하므로 실행중인 작업이 잠금을 해제 할 때까지 다음 테스트가 중단됩니다.

이것이이 질문과 완전히 관련이 없지만 올바른 문제를 타겟팅하는 데 도움이 될 수 있음을 알고 있습니다.


0

다음 코드 중 하나를 사용할 수 있습니다.

@FixMethodOrder(MethodSorters.JVM)OR `@FixMethodOrder(MethodSorters.DEFAULT)` OR `@FixMethodOrder(MethodSorters.NAME_ASCENDING)` before your test class like this:


@FixMethodOrder(MethodSorters.NAME_ASCENDING)


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