143

統合テスト スイートがあります。IntegrationTestBaseすべてのテストを拡張するためのクラスがあります。この基本クラスには、API および DB 接続を確立するための@Before( public void setUp()) および@After( ) メソッドがあります。public void tearDown()私がやっていることは、各テストケースでこれら 2 つのメソッドをオーバーライドし、 と を呼び出すことだけsuper.setUp()ですsuper.tearDown()。ただし、誰かがスーパーを呼び出すのを忘れたり、間違った場所に配置したりして、例外がスローされ、最後または何かでスーパーを呼び出すのを忘れた場合、これは問題を引き起こす可能性があります。

私がやりたいことは、基本クラスにsetUpandメソッドを作成し、独自の注釈付きandメソッドを追加することです。いくつかの初期テストを実行すると、常に次の順序で呼び出されるように見えます。tearDownfinal@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?* }
}
4

6 に答える 6

145

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

@Before:

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

@After:

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

于 2011-05-20T19:24:06.557 に答える
25

のドキュメントに基づいて、正しい結論はメソッドに一意の名前を付けることだと思い@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オーバーライドすることはありません。必要に応じて、正確な名前を知っている必要があり、実行できます。setUptearDown

setUpこのアプローチの (マイナーな) 欠点: ユーザーは/の前後に何かが起こっていることを認識できませんtearDown。これらが抽象クラスによって提供されることを知る必要があります。しかし、それが彼らが抽象クラスを使用する理由だと思います

于 2013-07-09T13:58:14.547 に答える
2

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

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

それはあなたが望むものとは正確には異なりますが、基本的には、テストの実行中は常にDB接続を開いたままにし、最後に完全に閉じます。

于 2011-05-20T19:26:41.087 に答える
2

これはキャッチフレーズの質問に対する回答ではありませんが、質問の本文に記載されている問題に対する回答です。@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);
     }
 }
于 2015-11-02T01:39:17.110 に答える
2

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

于 2011-05-20T19:21:54.910 に答える