単体テストがクラスの静的状態を変更し、Foo
その後クリーンアップしないという問題があります。これは、単体テストが単独で実行された場合は成功する可能性がありますが、他の単体テストがその前に実行されると失敗する可能性があることを意味します。これは、状態が変化したためです。
の静的状態を変更し、必要なクリーンアップを追加するテストを探してコードを調べてきましたが、Foo
別のアイデアがありました: junit テストリスナーを使用して、Foo
各テストの実行後の静的状態を調べてみませんか? 、Foo
変更された状態のままである場合は失敗しますか? 次に、ビルドごとにいたずらなテストのリストを自動的に取得し、将来同様の問題を特定できます。
そこで、junit を実装し、RunListener
mypom.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
クリーンアップされる場合、リスナーのメソッドは変更された状態を認識し、誤ってエラーを発生させます。@AfterClass
testFinished
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 つの単体テストTestA
とTestB
、および 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 行以上のレガシー コード ベースをリファクタリングすることは、この段階ではオプションではありません。