@BeforeClass 및 상속-실행 순서


92

단위 테스트 (TestNG 5.10)의 기본으로 사용하는 추상 기본 클래스가 있습니다. 이 클래스에서는 테스트, 데이터베이스 매핑 설정 등을위한 전체 환경을 초기화합니다.이 추상 클래스에는 @BeforeClass초기화를 수행 하는 주석 이있는 메서드가 있습니다.

다음으로 @Test메서드와 메서드 가있는 특정 클래스로 해당 클래스를 확장합니다 @BeforeClass. 이러한 메소드는 환경의 클래스 별 초기화를 수행합니다 (예 : 데이터베이스에 일부 레코드 저장).

@BeforeClass어노테이션이있는 메소드 의 특정 순서를 적용하려면 어떻게 해야합니까? 확장 클래스의 클래스보다 먼저 실행될 추상 기본 클래스의 클래스가 필요합니다.

예:

abstract class A {
    @BeforeClass
    doInitialization() {...}
}

class B extends A {
    @BeforeClass
    doSpecificInitialization() {...}

    @Test
    doTests() {...}
}

예상 주문 :

A.doInitialization
B.doSpecificInitialization
B.doTests

실제 주문 :

B.doSpecificInitialization // <- crashes, as the base init is missing
(A.doInitialization        // <---not executed
 B.doTests)                // <-/

답변:


50

수업 @BeforeClass에 넣지 마십시오 abstract. 각 하위 클래스에서 호출하십시오.

abstract class A {
    void doInitialization() {}
}

class B extends A {
    @BeforeClass
    void doSpecificInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}

TestNG가 가지고있는 것 같습니다 @BeforeClass(dependsOnMethods={"doInitialization"}). 시도해보십시오.


10
그것은 기본적으로 내가 피하고 싶었던 것입니다. 슈퍼 (추상) 클래스의 메서드를 명시 적으로 호출 할 필요가 없습니다. 특히 A에서 상속하지만 자체 @BeforeClass 메서드가없는 클래스도 있습니다. 나는 그 목적을 위해서만 하나를 삽입해야 할 것입니다.
Dominik Sandjaja

5
dependsOnMethods해결 방법은 트릭을했다. "슈퍼 클래스 우선"접근 방식을 선호하지만 ...
Dominik Sandjaja 2010-01-25

1
"dependsOnMethod"를 사용하려면 "doInitialization"에 "@Test"주석을 추가하면 안됩니까? 기술적으로 그 자체로는 테스트가 아니기 때문에 문제입니다 ...
N3da

@BeforeClass 정적 메소드한다 주석
파브리 Stellato

109

편집 : 아래 답변은 JUnit 용 이지만 도움이 될 수 있기 때문에 어쨌든 여기에 남겨 둘 것입니다.

JUnit API 에 따르면 : "슈퍼 클래스의 @BeforeClass 메서드는 현재 클래스보다 먼저 실행됩니다."

나는 이것을 테스트했고 그것은 나를 위해 작동하는 것 같습니다.

그러나 @Odys가 아래에서 언급했듯이 JUnit의 경우 부모가 섀도 잉되기 때문에 하위 클래스 메서드 만 실행되지만 다른 방식으로 명명두 메서드 가 있어야합니다 .


56
원래 질문은 TestNG에 대한 것이었지만 JUnit을 검색 한 후 여기에 도착했으며 귀하의 답변이 도움이되었습니다. 감사합니다!
teabot

9
JUnit을 위해 당신이 필요 하지만 부모가 그림자되기 때문에 실행되는 경우에만 서브 클래스 메소드의 결과 것 그렇지 않으면 일을 같이 다른 이름의 두 가지 방법을 가지고.
Odys

2
@Odys, 이것을 언급 해 주셔서 대단히 감사합니다. 나는 서브 클래스의 "setup"메소드가 실행되고 수퍼 클래스의 메소드가 실행되지 않는 이유를 파악하기 위해 고심하고있었습니다. 당신은 저에게 엄청난 고통을 구했습니다!
Tom Catullo

당신은 내 하루를 만들었습니다. 감사!
raiks

7

public추상 클래스에 추가 하고 TestNG (6.0.1)는 전에 doInitialization ()을 실행했습니다 doTests. 클래스 A에서 doInitialization()제거하면 TestNG가 실행되지 않습니다 public.

public abstract class A {
 @BeforeClass
 doInitialization() {...}
}

class B extends A {    
 @Test
 doTests() {...}
}

1
그것은 사실이지만 관련이 없습니다. 클래스 때 작동하지 않습니다 B 또한@BeforeClass영업 이익의 경우와 같이, -annotated 방법.
jpaugh

1
나도 똑같이했다. 기본 메서드가 개인 경우 상속 순서가 누락 된 것 같습니다. 감사!
Manu

6

방금 5.11에서 예제를 시도했는데 먼저 기본 클래스의 @BeforeClass가 호출되었습니다.

testng.xml 파일을 게시 할 수 있습니까? A와 B를 모두 지정하고 B 만 필요합니다.

testng-users 메일 링리스트에서 자유롭게 후속 조치를 취하면 문제를 자세히 살펴볼 수 있습니다.

-세드릭


2
testng에 대한 .xml이 (명시 적으로) 정의되지 않았으며 Eclipse 및 Maven에서 실행됩니다.
Dominik Sandjaja

Eclipse에서 정확히 어떻게 실행하고 있습니까? 클래스 B를 마우스 오른쪽 버튼으로 클릭 하시겠습니까?
Cedric Beust

4

나는 이것을 겪었고 이것을 달성하는 또 다른 방법을 찾았습니다. 그냥 사용 alwaysRun@BeforeClass또는 @BeforeMethod당신이 예상하는대로 추상 클래스에서 작동합니다.

public class AbstractTestClass {
    @BeforeClass(alwaysRun = true)
    public void generalBeforeClass() {
        // do stuff
        specificBeforeClass();
    }
}

2

내가 실행할 때 : JUnitCore.runClasses (TestClass.class); 이클립스에서 실행하는 경우 : 어떤 이유로 기본 클래스를 실행하지 못합니다 . (Super.SetUpBeforeClass ();는 필요하지 않습니다 .) 해결 방법 : 기본 클래스를 명시 적으로 호출합니다. ( BaseTest.setUpBeforeClass (); ) 응용 프로그램에서 실행하는 경우 기본 클래스에 플래그를 지정하여 이미 설정되었는지 여부를 확인할 수 있습니다. 따라서 가능한 두 가지 방법 (예 : 개인 테스트의 경우 Eclipse에서, 빌드 릴리스의 경우 ANT를 통해)을 통해 실행하는 경우 한 번만 실행됩니다.

이것은 Eclipse의 버그이거나 최소한 예상치 못한 결과로 보입니다 ..


2

JUnit의 경우 : @fortega가 언급했듯이 : JUnit API에 따르면 "슈퍼 클래스의 @BeforeClass 메서드는 현재 클래스보다 먼저 실행됩니다."

그러나 같은 이름으로 두 메서드의 이름을 지정하지 않도록주의 하십시오 . 이 경우 부모 메서드는 자식 부모에 의해 숨겨집니다. 소스 .


1

@BeforeClass 메서드가 다음과 같은 하위 클래스에 의해 덮어 쓸 수도 있고 덮어 쓸 수도없는 빈 specificBeforeClass () 메서드를 호출하게하는 것은 어떻습니까?

public class AbstractTestClass {
  @BeforeClass
  public void generalBeforeClass() {
    // do stuff
    specificBeforeClass();
  }

  protected void specificBeforeClass() {}
}

public class SpecificTest {
  @Override
  protected void specificBeforeClass() {
    // Do specific stuff
  }

  // Tests
}

3
BeforeClass는 정적이어야하므로 junit으로이 작업을 수행 할 수 없습니다
madx

1

dependsOnMethod 사용할 수 있습니다.

예 : Spring ( AbstractTestNGSpringContextTests)의 경우

@BeforeClass(alwaysRun = true, dependsOnMethods = "springTestContextPrepareTestInstance")

1

수입 명세서를 확인하십시오. 그것은해야한다

import org.testng.annotations.BeforeClass;

아니

import org.junit.BeforeClass;


1

이것은 나를 위해 작동합니다.

abstract class A {
    @BeforeClass
    doInitialization() {...}
}

class B extends A {
    @Override
    @BeforeClass
    doInitialization() { 

       //do class specific init

    }   

    @Test
    doTests() {...}
}

1
이 코드가 수행하는 작업에 대한 간단한 설명을 추가하고 원래 질문에 대한 답변
Cray

0

수퍼 클래스의 BeforeClass 주석이 달린 메소드에서 호출되는 수퍼 클래스에서 추상 메소드 doSpecialInit ()를 작성하지 않겠습니까?

따라서 클래스를 상속하는 개발자는이 메서드를 구현해야합니다.


솔직히 말해서 제가이 질문을 한 후 지난 3 년 반 동안 논리조차 바뀌었을지도 모릅니다 ... ;-) 그래서 네, 아마도 이것은 아이디어 였을 수도 있고, 작동하지 않았을 수도 있습니다.-솔직히 말하지 않습니다. 생각해 내다.
Dominik Sandjaja 2013 년

0

여기에 또 다른 쉬운 해결책이 있습니다.

내 특별한 상황은 수퍼 클래스의 "BeforeClass"가 실행되기 전에 서브 클래스의 "BeforeClass"에서 모의 ​​서비스를 주입해야한다는 것입니다.

이렇게하려면-간단히 @ClassRule 하위 클래스에서 를 됩니다.

예를 들면 :

@ClassRule
public static ExternalResource mocksInjector = new ExternalResource() {
    @Override
    protected void before() {
        // inject my mock services here
        // Note: this is executed before the parent class @BeforeClass
    }
};

이게 도움이 되길 바란다. 이것은 "역"순서로 정적 설정을 효과적으로 실행할 수 있습니다.


0

오늘 비슷한 문제에 직면했습니다. 유일한 차이점은 기본 클래스가 추상이 아니라는 것입니다.

여기 내 경우

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

public class B extends A {
    @BeforeClass
    private void doSpecificInitialization() {...}

    @Test
    public void doTests() {...}
}

@BeforeClass클래스 A 의 메서드가 실행되지 않은 경우 가 발생했습니다 .

  • A.doInitialization ()-> 이것은 자동으로 실행되지 않았습니다.
  • B.doSpecificInitialization ()
  • B.doTests ()

개인 정보 수정과 재생 내가 TestNG를가 발견 실행되지 않습니다@BeforeClass 상속 클래스에서 주석 방법을 방법은 클래스 상속인에서 볼 수없는 경우

따라서 이것은 작동합니다.

public class A {
    @BeforeClass
    private void doInitialization() {...}
}

public class B extends A {
    @BeforeClass
    //Here a privacy modifier matters -> please make sure your method is public or protected so it will be visible for ancestors
    protected void doSpecificInitialization() {...}

    @Test
    public void doTests() {...}
}

결과적으로 다음이 발생합니다.

  • A.doInitialization ()
  • B.doSpecificInitialization ()
  • B.doTests ()

-1

제 경우에는 (JUnit) 기본 클래스와 파생 클래스에 setup ()이라는 동일한 메서드가 있습니다. 이 경우 파생 클래스의 메서드 호출되고 기본 클래스 메서드를 호출합니다.


-2

상속을 사용하여 이것을 달성하는 더 좋고 깨끗한 방법은 다음과 같습니다.

abstract class A {

    @BeforeClass
    void doInitialization() {}
}

class B extends A {

    @Override
    @BeforeClass
    void doInitialization() {
        super.doInitialization();
    }

    @Test
    void doTests() {}
}

1
부모 클래스의 메서드를 먼저 실행해야하는 경우 부모와 다른 자식 클래스의 메서드 이름을 지정하면됩니다 (동일한 서명이 있으면 다형성이 작동하기 때문입니다). 나는 그것이 더 깨끗한 방법이라고 믿습니다.
Anatolii Stepaniuk
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.