1

単体テストがクラスの静的状態を変更し、Fooその後クリーンアップしないという問題があります。これは、単体テストが単独で実行された場合は成功する可能性がありますが、他の単体テストがその前に実行されると失敗する可能性があることを意味します。これは、状態が変化したためです。

の静的状態を変更し、必要なクリーンアップを追加するテストを探してコードを調べてきましたが、Foo別のアイデアがありました: junit テストリスナーを使用して、Foo各テストの実行後の静的状態を調べてみませんか? 、Foo変更された状態のままである場合は失敗しますか? 次に、ビルドごとにいたずらなテストのリストを自動的に取得し、将来同様の問題を特定できます。

そこで、junit を実装し、RunListenermypom.xmlにリスナーを追加するように変更してmaven-surefire-plugin、テスト ケースごとにリスナーが実行されることを確認しました。

testFinished()簡単な解決策は、メソッドをオーバーライドしRunListenerて静的状態を確認することです。

public class FooChecker extends RunListener {
  @Override
  public void testFinished(Description description) throws Exception {
    if (fooClassInModifiedState()) {
      throw new IllegalStateException("Test " + description.getDisplayName()
            + " has left Foo in a modified state");
    }
  }
}

これは、次の形式のテストで機能します。

public class SomeTest {

  @Before
  public void setUpTest() {
    Foo.modifyState();
  }

  @After
  public void tearDownTest() {
    Foo.resetState();
  }

  @Test
  public void testCase1() {
    ...
  }

  @Test
  public void testCase2() {
    ...
  }

}

各テスト ケースの後、@Afterメソッドが呼び出され、状態がクリーンアップされます。次に、testFinished()junit 実行リスナーのメソッドが呼び出され、状態がリセットされたことを確認します。メソッドを削除する@Afterと、予想どおり、実行リスナーでエラーが発生します。

ここでの問題はtestFinished、junit 実行リスナーのメソッドが単体テストのメソッドの後@BeforeClassと前に呼び出されることです。@AfterClass単体テストで Foo の状態が変更され、メソッドで@BeforeClassクリーンアップされる場合、リスナーのメソッドは変更された状態を認識し、誤ってエラーを発生させます。@AfterClasstestFinished

public class SomeTest {

  @BeforeClass
  public void setUpClass() {
    Foo.modifyState();
  }

  @Test
  public void testCase1() {
    ...
  }

  @Test
  public void testCase2() {
    ...
  }

  @AfterClass
  public void tearDownClass() {
    Foo.resetState();
  }

}

ここでtestFinished()、実行リスナーのメソッドは、呼び出された後testCase1()で呼び出さtestCase2()れますが、メソッドが呼び出される前@AfterClassであるため、状態はFoo変更されず、実行リスナーはエラーを発生させます。それは正しい振る舞いではありません。

一般に、2 つの単体テストTestATestB、および junit run listenerListenerの場合、呼び出しシーケンスは次のようになります。

  • Listener.testRunStarted()
  • TestA.@BeforeClass
  • Listener.testStarted("TestA.testCase1)
  • TestA.@Before
  • TestA.testCase1()
  • TestA.@After
  • Listener.testFinished(TestA.testCase1)
  • Listener.testStarted("TestA.testCase2)
  • TestA.@Before
  • TestA.testCase2()
  • TestA.@After
  • Listener.testFinished(TestA.testCase2)
  • TestA.@AfterClass
  • TestB.@BeforeClass
  • Listener.testStarted("TestB.testCase1)
  • TestB.@Before
  • TestB.testCase1()
  • TestB.@After
  • Listener.testFinished(TestB.testCase1)
  • TestB.@AfterClass
  • Listener.testRunFinished()

私が望むのは、メソッドが単体テストで呼び出された後、次の単体テストでメソッドが呼び出される@AfterClass前に、変更された状態のチェックを実行することです。@BeforeClassこのようにして、単体テスト (個々のテスト ケースではない場合) が必要なクリーンアップを実行し、テストのセマンティクスを尊重することを保証できます。

RunListenerしかし、junitを使用してこれを実行し、maven Surefire プラグインを使用してテストを呼び出す方法がわかりません。

ここに解決策はありますか?

編集:現在存在するすべてのテストと将来追加されるすべてのテストに追加する必要があるため、状態をチェックする既存のテストにjunitクラスルールを追加することはオプションではありません。可能であれば、違反を自動的に発見するものが欲しいです。

編集: ここでの根本的な問題は、maven モジュールの各単体テストが同じ JVM で実行されることです。各単体テストを独自の JVM で (surefire の分岐オプションを設定して) 実行しようとしましたが、テストの実行に時間がかかりすぎました。そのため、複数の単体テスト用に単一の JVM を使用しています。

編集: もちろん、静的メソッドを使用することはそもそも悪い設計であり、状態を挿入するためのリファクタリングが推奨されますが、1,000,000 行以上のレガシー コード ベースをリファクタリングすることは、この段階ではオプションではありません。

4

0 に答える 0