エグゼクティブ サマリー:スレッドでアサーション エラーがスローされても、単体テストは終了しません。あるスレッドが別のスレッドをクラッシュさせてはならないため、これは理にかなっています。問題は、1) 最初のヘルパー スレッドがクラッシュしたときにテスト全体を失敗させるか、2) ループしてすべてのスレッドが完了した後に各スレッドの状態を判断する方法です (以下のコードを参照)。後者を行う 1 つの方法は、スレッドごとのステータス変数、たとえば「boolean[] statuses」を使用し、「statuses[i] == false」をスレッドが失敗したことを意味するようにすることです (これは、より多くの情報を取得するために拡張できます)。ただし、それは私が望んでいることではありません。アサーション エラーがスローされたときに、他の単体テストと同じように失敗するようにしたいのです。これは可能ですか?それは望ましいですか?
うんざりしたので、単体テストで多数のスレッドを生成し、それらにサービス メソッドを呼び出させることにしました。コードはおおよそ次のようになります。
Thread[] threads = new Thread[MAX_THREADS];
for( int i = 0; i < threads.length; i++ ) {
threads[i] = new Thread( new Runnable() {
private final int ID = threadIdSequenceNumber++;
public void run() {
try {
resultRefs[ID] = runTest( Integer.toString( ID ) ); // returns an object
}
catch( Throwable t ) {
// this code is EVIL - it catches even
// Errors - don't copy it - more on this below
final String message = "error testing thread with id => "
+ ID;
logger.debug( message, t );
throw new IllegalStateException( message, t );
// need to wrap throwable in a
// run time exception so it will compile
}
}
} );
}
この後、スレッドの配列をループして、それぞれを開始します。その後、すべてが完了するのを待ちます。最後に、結果参照に対していくつかのチェックを実行します。
for( Thread thread : threads )
thread.start();
logger.debug( "waiting for threads to finish ..." );
boolean done = false;
while( !done ) {
done = true;
for( Thread thread : threads )
if( thread.isAlive() )
done = false;
}
for( int i = 0; i < resultRefs.length; i++ ) {
assertTrue( "you've got the world messed, dawg!",
myCondition(resultRefs[i]) );
これが問題です。厄介な try-catch-throwable ブロックに気付きましたか? 何が起こっているのかを確認できるように、一時的なハックとして追加しました。runTest( String ) では、 assertNotNull( null ) など、いくつかのアサーションが作成されますが、別のスレッドにあるため、単体テストが失敗することはありません!!!!
私の推測では、どうにかしてスレッド配列を繰り返し処理し、それぞれのステータスをチェックし、スレッドが不適切な方法で終了した場合は手動でアサーション エラーを発生させる必要があると思います。この情報 (デッド スレッドのスタック トレース) を提供するメソッドの名前は?