32
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JUnit - @Rule・@ClassRule使用方法の備忘録

Last updated at Posted at 2016-04-27

はじめに

みなさんはJUnit使ってますか?

Java用のテスティングフレームワークはTestNGなどもありますが、JUnitを使っている人が多いと思います。

そんなJUnitの@Rule@ClassRuleについて、備忘録として自分なりにまとめてみました。
間違っている場合もありますのでご容赦ください。

なお、実装例のpackage文・import文は省略しています。

概要

@Rule@Before@After
@ClassRule@BeforeClass@AfterClassの代替だそうです。
実際にはもっといろいろなことが出来るようです。

今後@Before@Afterなどが非推奨となることはないとは思いますが、読めるようにはしておきたいですね。

TestRuleクラスについて

TestRuleクラスを継承したクラスのインスタンスを、テストクラスのpublicフィールドに代入しておくことによって、テストに関する便利な機能が使えます。
(@ClassRuleの場合はstaticにもしなければなりません。)

下記は、テストケース内で動的にテストケース名を取得する例です。

テストケース名を取得する
public class TestClass {
    // テストケース名を取得するルールを定義
    @Rule
    public TestName testName = new TestName();

    @Test
    public void testMethod() {
        System.out.println("Method Name is " + testName.getMethodName());
    }
}
実行結果
Method Name is testMethod

前処理・後処理の記述方法について

前処理・後処理を書くには、ExternalResourceクラスが便利です。
クラス名にResourceと付いてますが、特にリソースに関する処理でなくても大丈夫です。

このクラスをインスタンス化する際に、beforeafterメソッドをオーバーライドすることで、それぞれ前処理・後処理を定義できます。

よくある使い方としては、ログに関する処理です。

下記では、例としてテストクラス・ケース実行の前後にテストケース名を出力しています。

テストケース名はExternalResourceクラスと前述のTestNameクラスで出力し、テストクラス名はTestRuleクラスを自分で拡張して取得・出力しています。

テスト実行の前後にログを出力する
public class TestClass {
    // テストクラス名を出力するルールを作成
    @ClassRule
    public static TestRule classRule = new TestRule() {
        @Override
        public Statement apply(Statement arg0, Description arg1) {
            // Statementクラスの匿名クラスを作成し、
            // テストクラス名を出力するようにevaluateメソッドをオーバーライドする。
            return new Statement() {
                private final Description description = arg1;
                private final Statement base = arg0;

                @Override
                public void evaluate() throws Throwable {
                    // テスト実行前に行う処理
                    System.out.println("Class : " + this.description.getClassName() + " start.");

                    // テストを実行する
                    // このメソッドを実行すると、実際にテストケースが実行される。
                    base.evaluate();

                    // テスト実行後に行う処理
                    System.out.println("Class : " + this.description.getClassName() + "end.");
                }
            };
        }
    };


    // テストケース名を出力するルール
    @Rule
    public TestRule rule = new ExternalResource() {
        @Override
        public void before() {
            System.out.println("Method : " + testName.getMethodName() + "start.");
        }
        @Override
        public void after() {
            System.out.println("Method : " + testName.getMethodName() + "end.");
        }
    };
    @Rule
    public TestName testName = new TestName();


    @Test
    public void testMethod1() {
        System.out.println("testMethod1 runnning...");
    }

    @Test
    public void testMethod2() {
        System.out.println("testMethod2 runnning...");
    }
実行結果
Class : junit.TestClass start.
Method : testMethod1start.
testMethod1 runnning...
Method : testMethod1end.
Method : testMethod2start.
testMethod2 runnning...
Method : testMethod2end.
Class : junit.TestClassend.

テストクラス名を出力するルールについてですが、

  • TestRuleクラスの匿名クラスを作成し、
  • applyメソッドをオーバーライドし、
  • その戻り値としてStatementクラスの匿名クラスを作成し、
  • evaluateメソッドをオーバーライドし、
  • その中でテストクラス名の出力を行なっています。

ややこしいですが、やっていることはそれほど難しくないのですぐわかると思います。
@Before@Afterの代わりとして使うだけなら、このコードをコピペして、base.evaluate();の前後にやりたい処理を記述するだけです。

2016/09/09 追記

Java8のラムダ式を使うと、以下のように(比較的)簡潔に書けます。

テストケース実行の前後にテストクラス・ケース名を出力する
@Rule
public TestRule logRule = (Statement statement, Description description) -> new Statement() {
    @Override
    public void evaluate() throws Throwable {
        System.out.println("Start : " + description.getClassName() + "#" + description.getMethodName());
        try {
            statement.evaluate();
        } finally {
            // 例外発生時にも終了ログを出力する
            System.out.println("End : " + description.getClassName() + "#" + description.getMethodName());
        }
    }
};

補足

このコードの@Rule@ClassRuleは、親クラスに書いていてもちゃんと実行中のテストクラス・ケース名を取得してくれます。

おわりに

ログ処理、DB処理等で使うことがメインになりそうですが、もっとおもしろい使い方とかあるのか調べてみたいです。
(AOPのようなことができるみたいです。)
詳しくはJUnitの公式ドキュメントJavadoc等を参照してください。

32
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
32
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?