[java] Junit @ Before / @ After는 어떤 주문입니까?

통합 테스트 스위트가 있습니다. IntegrationTestBase모든 시험을 연장 할 수있는 수업이 있습니다. 이 기본 클래스에는 API 및 DB 연결을 설정 하는 @Before( public void setUp()) 및 @After( public void tearDown()) 메소드가 있습니다. 내가 해왔 단지 각 테스트 케이스에서 그 두 가지 방법을 무시하고 호출 super.setUp()하고 super.tearDown(). 그러나 누군가가 수퍼에게 전화하는 것을 잊거나 잘못된 장소에두면 예외가 발생하고 마지막으로 또는 뭔가를 슈퍼라고 부르는 것을 잊어 버린 경우 문제가 발생할 수 있습니다.

내가하고 싶은 것은 만들 것입니다 setUptearDown기본 클래스의 메소드를 final다음 단지 우리 자신의 주석 추가 @Before@After방법을. 초기 테스트를 수행하면 항상 다음 순서로 호출되는 것으로 보입니다.

Base @Before
Test @Before
Test
Test @After
Base @After

하지만 주문이 보장되지 않아 문제가 발생할 수 있다고 우려합니다. 나는 둘러 보았고 주제에 대해 아무것도 보지 못했습니다. 내가 할 수 있고 문제가 없는지 아는 사람이 있습니까?

암호:

public class IntegrationTestBase {

    @Before
    public final void setUp() { *always called 1st?* }

    @After
    public final void tearDown() { *always called last?* }
}


public class MyTest extends IntegrationTestBase {

    @Before
    public final void before() { *always called 2nd?* }

    @Test
    public void test() { *always called 3rd?* }

    @After
    public final void after() { *always called 4th?* }
}



답변

예,이 동작은 보장됩니다.

@Before:

@Before수퍼 클래스 의 메소드는 현재 클래스에서 대체되지 않는 한 현재 클래스 의 메소드보다 먼저 실행됩니다. 다른 순서는 정의되어 있지 않습니다.

@After:

@After수퍼 클래스에 선언 된 메소드는 현재 클래스에서 재정의되지 않는 한 현재 클래스 의 메소드 이후에 실행됩니다.


답변

전에 나를 물린 한 가지 잠재력이 있습니다.

@Before클래스 @Before내에서 정의 된 메소드 를 실행하는 순서 가 보장되지 않기 때문에 각 테스트 클래스마다 최대 하나의 메소드 를 갖고 싶습니다 . 일반적으로 이러한 메소드를 호출합니다 setUpTest().

그러나 @Before로 문서화되어 있지만 The @Before methods of superclasses will be run before those of the current class. No other ordering is defined.이것은 @Before클래스 계층에서 고유 한 이름을 가진 각 메소드 가있는 경우에만 적용됩니다 .

예를 들어, 나는 다음을 가졌다 :

public class AbstractFooTest {
  @Before
  public void setUpTest() { 
     ... 
  }
}

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() { 
    ...
  }
}

나는 AbstractFooTest.setUpTest()전에 달릴 것으로 예상 FooTest.setUpTest()했지만 FooTest.setupTest()처형되었다. AbstractFooTest.setUpTest()전혀 호출되지 않았습니다.

작동하려면 코드를 다음과 같이 수정해야합니다.

public void FooTest extends AbstractFooTest {
  @Before
  public void setUpTest() {
    super.setUpTest();
    ...
  }
}


답변

나는의 문서를 기반으로 생각 @Before하고 @After올바른 결론은 방법에게 고유 한 이름을 제공하는 것입니다. 테스트에서 다음 패턴을 사용합니다.

public abstract class AbstractBaseTest {

  @Before
  public final void baseSetUp() { // or any other meaningful name
    System.out.println("AbstractBaseTest.setUp");
  }

  @After
  public final void baseTearDown() { // or any other meaningful name
    System.out.println("AbstractBaseTest.tearDown");
  }
}

public class Test extends AbstractBaseTest {

  @Before
  public void setUp() {
    System.out.println("Test.setUp");
  }

  @After
  public void tearDown() {
    System.out.println("Test.tearDown");
  }

  @Test
  public void test1() throws Exception {
    System.out.println("test1");
  }

  @Test
  public void test2() throws Exception {
    System.out.println("test2");
  }
}

결과적으로 주다

AbstractBaseTest.setUp
Test.setUp
test1
Test.tearDown
AbstractBaseTest.tearDown
AbstractBaseTest.setUp
Test.setUp
test2
Test.tearDown
AbstractBaseTest.tearDown

이 방법의 장점 : AbstractBaseTest 클래스의 사용자는 실수로 setUp / tearDown 메소드를 대체 할 수 없습니다. 그들이 원한다면 정확한 이름을 알아야 할 수 있습니다.

이 접근 방식의 단점 : 사용자는 setUp / tearDown 이전 또는 이후에 발생하는 상황을 알 수 없습니다. 그들은 이러한 것들이 추상 클래스에 의해 제공된다는 것을 알아야합니다. 그러나 그것이 추상적 클래스를 사용하는 이유라고 생각합니다.


답변

상황을 바꾸면 기본 클래스 추상을 선언하고 자손이 기본 클래스의 주석이 달린 setUp 및 tearDown 메서드에서 호출되는 setUp 및 tearDown 메서드 (주석없이)를 선언하도록 할 수 있습니다.


답변

@BeforeClass주석을 사용 하여 setup()항상 먼저 호출 되도록 할 수 있습니다 . 마찬가지로 @AfterClass주석을 사용 하여 tearDown()항상 마지막에 호출 되도록 할 수 있습니다 .

이것은 일반적으로 권장되지 않지만 지원됩니다 .

정확히 원하는 것은 아니지만 테스트가 실행되는 동안 DB 연결을 기본적으로 열어 놓은 다음 끝까지 한 번에 닫으십시오.


답변

이것은 태그 라인 질문에 대한 답변이 아니지만 질문 본문에 언급 된 문제에 대한 답변입니다. @Before 또는 @After를 사용하는 대신 @ org.junit.Rule 을 사용 하면 유연성이 향상됩니다. 연결을 관리하는 경우 ExternalResource (4.7 현재)가 가장 관심이있는 규칙입니다. 또한 규칙의 실행 순서를 보장하려면 RuleChain (4.10 기준)을 사용하십시오. 이 질문을 받았을 때이 모든 것이 가능하다고 생각합니다. 아래 코드 예제는 ExternalResource의 javadoc에서 복사되었습니다.

 public static class UsesExternalResource {
  Server myServer= new Server();

  @Rule
  public ExternalResource resource= new ExternalResource() {
      @Override
      protected void before() throws Throwable {
          myServer.connect();
         };

      @Override
      protected void after() {
          myServer.disconnect();
         };
     };

  @Test
  public void testFoo() {
      new Client().run(myServer);
     }
 }


답변