My Photo

« JUnit その4:ルール | Main | 新潟ミシェウの技ありゴールで勝利、磐田アウェイで3発快勝 »

August 24, 2012

JUnit その5:カスタムルール

カスタムルール

org.junit.rules.TestRuleインタフェースを実装することで独自のルールを作成できる。
TestRuleインタフェースは次のメソッドが定義されている。

Statement apply(Statement base, Description description)
戻り値:
新しいStatement。それはbaseと同じもの、baseのラッパー、あるいは完全に新しいStatementかもしれない。

StatementはJUnitのテストを実行するオブジェクト。このクラスには evalute() が定義されている。
evalute() は次のような処理を実行する。

  1. テストクラスのインスタンスの生成
  2. @Beforeの付与されたメソッドの実行(初期化)
  3. テストメソッドの事項
  4. @Afterの付与されたメソッドの実行(後処理)

多くのカスタムルールのapply()はbase(オリジナルのStatement)の前後で独自の処理を実行するStatment、つまりプロキシオブジェクト(ドキュメントで言ってるところのラッパー)を返す。

Descriptionテストケースのメタ情報を保持する。

次のコードはアサーション失敗時のAssertionErrorを拡張するカスタムルール。
JUnitではテスト失敗時にjava.lang.AssertionErrorが送出され、フレームワーク層まで伝達されたエラー情報が表示される。
しかしパラメータ化されたテストではAssertionErrorniテストで使用したパラメータが含まれない。下記カスタムルールにパラメータ情報を追加すれば、テスト失敗のAssertionErrorにパラメータが含まれ、パラメータもエラー情報として表示されるようになる。

package junit.tutorial;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

/**
 * アサーション失敗時の情報を拡張するカスタムルール
 */
public class AssertionMessage implements TestRule {
	
	private StringBuilder msg = new StringBuilder();
	
	public void append(String format, Object... params) {
		msg.append(String.format(format, params));
	}
	
	public String getMessage() {
		return msg.toString();
	}

	@Override
	public Statement apply(final Statement base, Description desc) {
		return new Statement() {
			
			@Override
			public void evaluate() throws Throwable {
				try {
					base.evaluate();
				} catch (AssertionError e) {
					AssertionError e2;
					if (msg.length() > 0) {
						msg.append('\n').append(e.getMessage());
						e2 = new AssertionError(msg.toString());
						e2.setStackTrace(e.getStackTrace());
					} else {
						e2 = e;
					}
					throw e2;
				}
			}
		};
	}
}

次のコードは上記のカスタムルールを適用したCalculatorクラスのテストクラス(乗算のみ)。

package junit.tutorial;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Rule;
import org.junit.experimental.runners.Enclosed;
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

/**
 * AssertionMessageルールを適用したCalculatorのテストクラス
 */
@RunWith(Enclosed.class)
public class CalculatorRuledTest {

	@RunWith(Theories.class)
	public static class 乗算メソッドのパラメータ化テスト {
		
		@DataPoint public static Fixture DATA1 = new Fixture(3, 4, 12);
		@DataPoint public static Fixture DATA2 = new Fixture(5, 7, 12);
		
		@Rule
		public AssertionMessage message = new AssertionMessage();
		
		@Theory
		public void multiplyで乗算結果が取得できること(Fixture fx) {
			message.append("case: %d * %d = %d", fx.x, fx.y, fx.expected);
			System.out.println(message.getMessage());
			Calculator calc = new Calculator();
			int expected = fx.expected;
			int actual = calc.multiply(fx.x, fx.y);
			assertThat(actual, is(expected));
		}
		
		static class Fixture {
			int x, y, expected;

			Fixture(int x, int y, int expected) {
				this.x = x;
				this.y = y;
				this.expected = expected;
			}
		}
	}	
}

参考記事:WEB DB PRESS Vol.69 JUnit実践入門

参考サイト:
JUnit 4.9の@ClassRuleでクラス単位の前後処理 - 裏紙

« JUnit その4:ルール | Main | 新潟ミシェウの技ありゴールで勝利、磐田アウェイで3発快勝 »

「Java」カテゴリの記事

Comments

Post a comment

(Not displayed with comment.)

TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/26461/55499360

Listed below are links to weblogs that reference JUnit その5:カスタムルール:

« JUnit その4:ルール | Main | 新潟ミシェウの技ありゴールで勝利、磐田アウェイで3発快勝 »

April 2017
Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof