メモ: テスト対象メソッドの実行後、テストメソッドは即座に終了される

昨日の続き。というより、訂正です。

JUnitのRuleアノテーションの使い方を知って喜んでいましたが、1つのテストメソッドの中では、1回だけしかテスト対象コードの呼び出しを書いてはいけなかったようです。

コメントで教えていただきました(ありがとうございます)。昨日の記事のテストコードは、修正済みです。

たとえば、次のコードを実行すると・・・

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class DeckTest {

        Deck deck;

        @Rule
        public ExpectedException thrown = ExpectedException.none();

        @Test
        public void testDivideCardsForException() throws Exception {
                // ※注 このテストメソッドは、よくない例
                
                deck = new Deck();

                thrown.expect(IllegalArgumentException.class);
                thrown.expectMessage("山札は1枚以上なければならない。");
                System.out.println("hoge");    // (1)
                deck.divideCards(0, 2);    // 1回目のテスト対象コードの呼び出し

                thrown.expect(IllegalArgumentException.class);
                thrown.expectMessage("プレイヤー数は2以上でなければならない。");
                System.out.println("moga");    // (2)
                deck.divideCards(2, 0);    // 2回目のテスト対象コードの呼び出し
        }
}

テストはグリーンになって成功します。

しかし、標準出力を見ると、

hoge

1回目のテスト対象メソッドの呼び出ししか、評価されていないことが分かります。

ちなみに、テスト対象メソッドの呼び出しの直前と直後にメッセージを出力すると、

	@Test
	public void testDivideCardsForDeckException() throws Exception {
		deck = new Deck();

		thrown.expect(IllegalArgumentException.class);
		thrown.expectMessage("山札は1枚以上なければならない。");
		System.out.println("hoge");    // (1)
		deck.divideCards(0, 2);    // テスト対象コードの呼び出し
		System.out.println("moga");    // (2)
	}

直前のメッセージだけが表示されます。

hoge

テスト対象コードの呼び出しまでしか実行されないのですね。

JUnit先生のRunnerの動きをよく理解していませんでした。

というわけで、ExpectExceptionがどんなふうに実行されるのか少し見てみようと思って、テスト対象メソッドの呼び出しにブレークポイントを置き、ひとまずデバッグ実行してみました。

ReflectiveCallable.runメソッドから、ExpectedException.evaluateメソッド、RanRules.evaluateメソッドが呼び出されます。ここで、あらかじめ設定しておいた例外の型や、メッセージ文字列が、Matcherを使って確認されます。

確認が終わったら、ParentRunner.runLeafのfinalyブロックに入ります。(ここまで実行してきたのが、tryブロックにあるstatement.evaluate()だったんですね)

		try {
		    statement.evaluate();
		} catch (AssumptionViolatedException e) {
			eachNotifier.addFailedAssumption(e);
		} catch (Throwable e) {
			eachNotifier.addFailure(e);
		} finally {
			eachNotifier.fireTestFinished();
		}

fireTestFinishedメソッドは、RunNotifierのメソッドです。「Invoke to tell listeners that an atomic test finished. 」というJavadocコメントがありました。

		new SafeNotifier() {
			@Override
			protected void notifyListener(RunListener each) throws Exception {
				each.testFinished(description);
			};
		}.run();

例外を調査したら、さっさと実行を終えてしまうらしいことだけは、分かりました。

本当はもっと詳しく読んでみるべきところですが、今日はここまで(^^;