66

setUp(@Before)はテストメソッドの前に実行され、tearDown(@After)はテストメソッドの後に実行されることは誰もが知っていると思います。

また、JunitがテストメソッドごとにTestのインスタンスを1つ作成することもわかっています。

私の質問は、setUpメソッドのコンテンツをクラスConstructorに移動して、setUpメソッドを削除できるかどうかです。setUpメソッドを保持する特別な理由はありますか?

4

6 に答える 6

59

この(古い)JUnitのベストプラクティスの記事では、次のように説明しています。

テストケースコンストラクターを使用してテストケースを設定しないでください

コンストラクターでテストケースを設定することはお勧めできません。検討:

public class SomeTest extends TestCase
   public SomeTest (String testName) {
      super (testName);
      // Perform test set-up
   }
}

セットアップの実行中に、セットアップコードが。をスローすることを想像してみてください IllegalStateException。それに応じて、JUnitはをスローし AssertionFailedError、テストケースをインスタンス化できなかったことを示します。結果のスタックトレースの例を次に示します。

junit.framework.AssertionFailedError: Cannot instantiate test case: test1   
    at junit.framework.Assert.fail(Assert.java:143)
    at junit.framework.TestSuite.runTest(TestSuite.java:178)
    at junit.framework.TestCase.runBare(TestCase.java:129)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    at junit.framework.TestCase.run(TestCase.java:120)
    at junit.framework.TestSuite.run(TestSuite.java, Compiled Code)
    at junit.ui.TestRunner2.run(TestRunner.java:429)

このスタックトレースは、情報量が少ないことがわかります。テストケースをインスタンス化できなかったことを示しているだけです。元のエラーの場所や発生場所の詳細は示されていません。この情報の欠如により、例外の根本的な原因を推測することは困難です。

コンストラクターでデータを設定する代わりに、をオーバーライドしてテスト設定を実行しますsetUp()。スローされた例外setUp()はすべて正しく報告されます。このスタックトレースを前の例と比較してください。

java.lang.IllegalStateException: Oops
    at bp.DTC.setUp(DTC.java:34) 
    at junit.framework.TestCase.runBare(TestCase.java:127)
    at junit.framework.TestResult.protect(TestResult.java:100)
    at junit.framework.TestResult.runProtected(TestResult.java:117)
    at junit.framework.TestResult.run(TestResult.java:103)
    ...

このスタックトレースは、はるかに有益です。どの例外がスローされたか(IllegalStateException)とどこからスローされたかを示します。これにより、テストセットアップの失敗を説明するのがはるかに簡単になります。

于 2010-09-06T02:50:38.867 に答える
26

仕事で私たちはあなたの質問に答えるかなり面白いものを発見しました。テストスイート、特に大量のテスト(200以上)を実行すると、JUnitは大量のメモリを使用し始めます。これは、実際のテストメソッドが実行される前にすべてのテストがインスタンス化されるためです。

これが原因で「メモリリーク」が発生しました。これは、Springを使用してデータベーステスト用に一部のJPA EntiryManagerオブジェクトをワイヤリングしたためです。これは、大量のオブジェクトと大量のメモリになり、テストの約半分でOutOfMemory例外が発生しました。 。

私見ですが、ベストプラクティスは、setUpとtearDownを使用して依存関係を挿入し、すべてのクラス参照を無効にすることです。これにより、テストの実行が速くなり、頭痛の種を大幅に減らすことができます。

あなたが私たちの過ちから学ぶことを願っています:)

于 2010-09-06T22:54:00.977 に答える
24

ここに3つの理由があります。要約すれば:

  1. 状況によっては、テストケースが実行される直前まで、テストフィクスチャのセットアップを可能な限り延期することを好む場合があります。

  2. 一部のテストケースは、深いテストケース継承階層の一部である場合があります。コンストラクターの完全な階層が完了するまで、テストフィクスチャのセットアップを延期することが望ましい場合があります。

  3. コンストラクターで失敗した場合よりも、setUp()でセットアップコードが失敗した場合の方が、より適切な診断が得られます。

1.テストケースの直前までフィクスチャのセットアップを延期します

使いやすさのためのデザイン
http://www.artima.com/weblogs/viewpost.jsp?thread=70189

...そして、Elliotte Rusty Haroldが言ったように、テストメソッドごとに新しいTestCaseインスタンスを作成する場合、「なぜsetUp()メソッドに煩わされるのですか?」TestCaseコンストラクターを使用できます。

Bruce Eckelが、setUp()でフィクスチャを作成することと、TestCaseコンストラクタでフィクスチャを作成することには微妙な違いがあると指摘していると聞きました。JUnitは、すべてのTestCaseインスタンスを事前に作成してから、インスタンスごとに、setup()、testメソッド、およびtearDown()を呼び出します。つまり、微妙な違いは、コンストラクターがすべて前もってバッチで呼び出されるのに対し、setUp()メソッドは各テストメソッドの直前に呼び出されることです。しかし、これは実際にはそれほど有用な違いではないようです。

2.すべてのテストケースがインスタンス化されるまで、フィクスチャのセットアップを延期します

ETutorialのJavaエクストリームプログラミング-4.6セットアップとティアダウン
http://etutorials.org/Programming/Java+extreme+programming/Chapter+4.+JUnit/4.6+Set+Up+and+Tear+Down/

テストケースのコンストラクターでフィールドを単純に初期化するのではなく、なぜsetUp()メソッドを作成する必要があるのか​​疑問に思われるかもしれません。結局のところ、テストケースの新しいインスタンスがそのテストメソッドごとに作成されるため、コンストラクターは常にsetUp()の前に呼び出されます。ほとんどの場合、副作用なしにsetUp()の代わりにコンストラクターを使用できます。

テストケースがより深い継承階層の一部である場合、派生した[test]クラスのインスタンスが完全に構築されるまで、オブジェクトの初期化を延期することをお勧めします。これは、初期化にコンストラクターの代わりにsetUp()を使用することをお勧めする技術的な理由です。setUp()とtearDown()を使用すると、コードが読みやすくなる可能性があるため、ドキュメントの目的にも適しています

3.セットアップが失敗した場合のより良い診断

JUnitのベストプラクティス(JavaWorld)
http://www.javaworld.com/jw-12-2000/jw-1221-junit.html

コンストラクターでテストケースを設定することはお勧めできません。..。

[テストケースコンストラクターでセットアップが行われるコードで]セットアップの実行中に、セットアップコードがIllegalStateExceptionをスローすることを想像してみてください。応答として、JUnitはAssertionFailedErrorをスローし、テストケースをインスタンス化できなかったことを示します。..。

[テストケースコンストラクターのセットアップコードでスローされた例外の]このスタックトレースは、かなり有益ではないことがわかります。テストケースをインスタンス化できなかったことを示しているだけです。

コンストラクターでデータを設定する代わりに、setUp()をオーバーライドしてテスト設定を実行します。setUp()内でスローされた例外は、正しく報告されます。..。

このスタックトレース[テストケースコンストラクターの代わりにsetUp()メソッドでスローされた例外の]は、はるかに有益です。どの例外がスローされたか(IllegalStateException)、どこから発生したかを示します。これにより、テストセットアップの失敗を説明するのがはるかに簡単になります。

于 2010-09-06T04:01:28.393 に答える
6

などのカスタムランナーは、コンストラクターとメソッドSpringJUnit4ClassRunnerの間でいくつかのコードを実行する必要がある場合があります。@Beforeこの場合、ランナーは@Beforeメソッドが必要とする依存関係を注入する可能性があります。ただし、依存性注入は、オブジェクトが構築された後にのみ実行できます。

于 2010-09-06T03:02:20.453 に答える
3

これが必要な理由は、多くのテストでは、各テストの前に状態を初期化して、すべてのテストが実行中の開始状態について想定できるようにする必要があるためです。

テストクラスがラップするとします。たとえば、データベースアクセスです。各テストの後で、テストによってデータベースに加えられた変更をすべて削除する必要があります。削除しなかった場合、各テストはわずかに変更されたデータベースに対して実行されます。さらに、以前のテストの一部のサブセットが失敗した場合、特定のテストで異なる一連の変更が発生する可能性があります。たとえば、test1が挿入を実行し、test2がテーブルサイズを正確に読み取っていることを確認するとします。1日目、test1は失敗し、0は正しいです。2日目、test1は成功し、1は正しいですか?

ところで、junit@BeforeClassはグローバルセットアップを実行する場合にもサポートし、セットアップとティアダウンはオプションです。

于 2010-09-06T02:36:50.610 に答える
-4

私はいくつかの理由が次のようにすべきだと思います:

  1. @BeforeコンテンツをConstructorに移動する場合、それは問題ありませんが、@ Afterコンテンツを移動する場所はありますか?
  2. コンストラクターと@Before/ @ Afterの違いは、コンストラクターを使用してクラスのインスタンスを作成する必要があることです。@ Before / @ Afterは、テストケースリソースを準備するためのものです。
于 2010-09-18T13:06:13.543 に答える