web-dev-qa-db-ja.com

setUp / tearDown(@ Before / @ After)JUnitでそれらが必要な理由

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

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

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

61
mhshams

この(古い) 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)
_

このスタックトレースは、かなり有益ではありません。テストケースをインスタンス化できなかったことを示すだけです。元のエラーの場所やOriginの場所については詳しく説明しません。この情報不足により、例外の根本的な原因を推測することが難しくなります。

コンストラクターでデータをセットアップする代わりに、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)とその発生元を示します。これにより、テストのセットアップの失敗を簡単に説明できます。

58
Pascal Thivent

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

データベーステストのためにいくつかのJPA EntiryManagerオブジェクトにSpringをワイヤリングするためにSpringを使用したため、これが原因で「メモリリーク」に遭遇しました。 。

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

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

24
BjornS

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

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

ETutorial's Java Extreme Programming-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)およびどこから発生したかを示します。 テスト設定の失敗を説明するのがはるかに簡単になります。

23
Bert F

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

6
RichN

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

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

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

3
Steve B.