web-dev-qa-db-ja.com

Junit @ Before / @ Afterはどの順序で呼び出されますか?

Integration Test Suiteを持っています。すべてのテストを拡張するためのIntegrationTestBaseクラスがあります。この基本クラスには、API接続とDB接続を確立する@Beforepublic void setUp())および@Afterpublic void tearDown())メソッドがあります。私がやっていることは、各テストケースでこれらの2つのメソッドをオーバーライドし、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?* }
}
126
Joel

はい、この動作は保証されています:

@Before

スーパークラスの@Beforeメソッドは、現在のクラスでオーバーライドされない限り、現在のクラスのメソッドの前に実行されます。他の順序は定義されていません。

@After

スーパークラスで宣言された@Afterメソッドは、現在のクラスでオーバーライドされない限り、現在のクラスのメソッドの後に実行されます。

127
axtavt

以前に私を噛んだことのある潜在的な落とし穴:

クラス内で定義された@Beforeメソッドの実行順序が保証されていないため、各テストクラスに最大で1つの@Beforeメソッドが必要です。通常、このようなメソッドsetUpTest()を呼び出します。

ただし、@BeforeThe @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();
    ...
  }
}
48
John Q Citizen

@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の前後に発生していることを確認できません。これらは、抽象クラスによって提供されることを知る必要があります。しかし、それが抽象クラスを使用する理由だと思います

20
Matthias Hoefel

@BeforeClassアノテーションを使用して、setup()が常に最初に呼び出されるようにすることができます。同様に、@AfterClass注釈を使用して、tearDown()が常に最後に呼び出されるようにすることができます。

通常、これは推奨されませんが、 サポート です。

望みどおりではありませんが、テストの実行中は基本的にDB接続を開いたままにし、最後に一度だけ閉じます。

2
Swati

これは、キャッチフレーズの質問に対する答えではありませんが、質問の本文で言及されている問題に対する答えです。 @Beforeまたは@Afterを使用する代わりに、 @ org.junit.Rule の使用を検討してください。これにより、柔軟性が向上します。 ExternalResource (4.7現在)は、接続を管理する場合に最も関心のあるルールです。また、ルールの実行順序を保証したい場合は、 RuleChain (4.10以降)を使用します。この質問が尋ねられたとき、これらはすべて利用可能であったと思います。以下のコード例は、ExternalResourceのjavadocsからコピーされています。

 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);
     }
 }
2
successhawk

物事を好転させる場合は、基本クラスの抽象を宣言し、子孫に基本クラスの注釈付きsetUpおよびtearDownメソッドで呼び出されるsetUpおよびtearDownメソッド(注釈なし)を宣言させることができます。

2
Buhb