前回も触れましたが、slim3 のテストでは jUnit 4.7 を使用しています。
jUnit は、4.x 系になってから、仕様がアノテーションベースに変更になっています。
前回はうまくまとめられなかったので、今回は jUnit 4.x 系の使い方を簡単にまとめてみようと思います。
ポイント
4.x 系の場合、大きく2つのポイントがあります。
- TestCase を継承しない
- アノテーションを使用する
TestCaseを継承しない
4.x 系では、@Test アノテーション(後述)をテストメソッドにつければテスト対象として認識されます。
そのため、3.x 系までのように org.junit.TestCase クラスを継承する必要はありません。
※特別にクラスを継承することは可能。Service のテストで触れる予定。
但し、TestCase クラスを継承しなくなると、assertXxx() などのメソッドを修飾子なしで呼び出すことができなくなり面倒です。
(例えば、assertXxx() は本来 org.junit.Assert クラスのメソッドで、TestCase がラップしているため、修飾子なしで呼び出すことができます。)
そのため 4.x 系では、以下のように、該当の static インポートを追加することになります。
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*;
slim3 の環境構築手順で、org.hamcrest.CoreMatchers などをコンテンツアシストに追加したのは、
上記に円滑に対応するためです。(たぶん)
アノテーションを使用する
4.x 系では、以下のアノテーションをメソッドに付記して、テストコードを作成していきます。
アノテーション | 意味 | FQN |
---|---|---|
@Test | テスト対象メソッド | org.junit.Test |
@Test(expected=例外クラス.class) | 指定した例外が発生したらOK | org.junit.Test |
@Test(timeout=ミリ秒) | 指定時間をオーバーしたらNG | org.junit.Test |
@Ignore("comment") | 一時的にテスト対象外とする(@Testにつける) | org.junit.Ignore |
@Before | これまでの setUp() に相当するもの | org.junit.Before |
@After | これまでの tearDown() に相当するもの | org.junit.After |
@BeforeClass | 全テスト実行前に1回だけ実施される前処理 | org.junit.BeforeClass |
@AfterClass | 全テスト実行後に1回だけ実施される後処理 | org.junit.AfterClass |
プログラム例と実行結果例
import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; // モデル Order のテストという前提 public class OrderTest { // テスト対象 private Order target = null; @Before public void before() { System.out.println("setUp"); this.target = new Order(); } @After public void after() { System.out.println("tearDown"); this.target = null; } // 全テストで1回だけ実施 @BeforeClass public static void beforeAll() { System.out.println("beforeAll"); } // 全テストで1回だけ実施 @AfterClass public static void afterAll() { System.out.println("afterAll"); } // ↓テストケース // 通常のケース @Test public void test() throws Exception { assertThat(this.target, is(notNullValue())); } // 例外発生の検証 @Test(expected=NullPointerException.class) public void expectError() { this.target = null; this.target.toString(); } // 無視の検証 @Test(expected=IllegalArgumentException.class) @Ignore("test") public void unexpectError() { this.target = null; this.target.toString(); System.out.println("This case will be ignored"); } // 想定時間内に処理が終了することの検証 @Test(timeout=1000) public void testTimeout() { for (int i = 0; i < 1000; i++) { System.out.println("sleeping..."); } } }
実行結果
beforeAll setUp tearDown setUp tearDown setUp sleeping... 〜(略) tearDown afterAll
気がついた点
(1)Before/After/BeforeClass/AfterClass は public
public にしないと、以下のエラーが発生します。
java.lang.Exception: Method xxx() should be public
(2)Before/After/BeforeClass/AfterClass は void
void にしないと、以下のエラーが発生します。
java.lang.Exception: Method xxx() should be void
(3)BeforeClass/AfterClass は static
static にしないと、以下のエラーが発生します。
java.lang.Exception: Method xxx() should be static
(4)Before/After/BeforeClass/AfterClass のメソッド名は自由
@Before で after() とか命名できますが…混乱するので避けましょうw
(5)Ignore は Before/After/BeforeClass/AfterClass には効かない
@Ignore は、テストメソッドにのみ効果があるようです。
(6)Before/After/BeforeClass/AfterClass は複数指定可能
実行順序が問題。
後で調べます。