JUnit4メモ

2008/05に書いたメモをブログ化。

概要

  • 単体テストのためのオープンソースのテスティングフレームワークである.
  • Javaにおいては標準的なテスティングフレームワークである.Kent Ceck氏やErich Gamma氏が中心となって作成した.
  • JUnit3プラグインとJUnit4プラグイン(Java5対応,JUnit3の制約を排除)がEclipseに同梱されている.Eclipse上での単体テストの代名詞.
  • 個々のクラスについてテストクラスを提供し,テストしたいメソッドの実行結果とその期待値を評価して,そのテスト結果を報告する.
    • 期待される正解をあらかじめテストに書いておいて,テスト自身に実行結果が正しいかどうかをチェックさせる
  • 複数のテストを一度に簡単に実行でき,結果も一目でわかる.

特徴

  • テスト自体は Java言語で開発者自信が記述する
  • テストは自動で実行され,結果はすぐにフィードバックされる
  • 複数のテストを論理的な階層にまとめることができる

利用手順

1. プロジェクトのビルドパスのライブラリに JUnit4ライブラリを追加.
2. テスト対象クラスのテストクラス(対象クラス名の末尾に"Test"を付けた名前で)を生成する(:テスト対象クラスを右クリック→新規作成→JUnitテスト・ケース)
(※ソース用ディレクトリ(src)とは別にテスト用ディレクトリ(test)を用意するのがよい.通常,テスト対象とテストクラスは同一パッケージにしておく.(⇒論理的には同一パッケージで物理的には別のディレクトリにある))
3. テストクラスの中身を記述する.
4. テストクラスを org.junit.runner.JUnitCore の引数として渡して実行する(:テストクラスを右クリック→Run As→JUnit Test)(=コマンドラインから「 java org.junit.runner.JUnitCore <テストクラス> 」を実行)
5. JUnitビューに切り替わり,テスト結果が表示される.

慣例となっている命名方法
  • テストクラス名: <対象クラス名>Test
  • テストメソッド名: test<対象メソッド名の接頭辞を大文字にしたもの>

JUnitの内部動作

1. テストクラスのインスタンスの生成
2. @BeforeClass の付いたメソッドを実行
3. 以下の 3.1〜3.3 をテストメソッドの個数回(順不同)だけ繰り返す.
3.1. @Before の付いたメソッド(JUnit3ではsetUp()メソッド)を実行
3.2. @Test の付いたメソッドを実行
3.3. @After の付いたメソッド(JUnit3ではtearDown()メソッド)を実行
4. @AfterClass の付いたメソッドを実行

テスト失敗の厳密な区別
  • テストメソッドから例外が投げられた場合⇒エラー(Errors)としてカウント (テストメソッドでキャッチされなかった例外はJUnitフレームワーク自信がキャッチして,テスト失敗として扱ってくれる.それゆえ,テストメソッド内で無理にtry-catchを書く必要が無い)
  • アサーションが失敗した場合⇒失敗(Failure)としてカウント

テストクラスの形式(JUnit4)

JUnitフィクスチャ・アノテーション
  • @Test
    • @Test(expected=<例外クラス名>.class)
    • @Test(timeout=<ミリ秒単位の数値>)
    • テストメソッドに付ける.
    • public voidメソッドに付けることができる.
    • expected はテストメソッドが出す例外を宣言するためのもの.宣言された例外が出されなかったなら,失敗が報告される.
  • timeout はテストの実行時間を宣言するためのもの.宣言された時間内にテストが終了しなかったなら,失敗が報告される.
  • @Before
    • テストケースの中で繰り返し使われる共通オブジェクトの初期化に使われる.
    • public voidメソッドに付けることができる.
  • @After
    • テストメソッド実行後にリソースを開放するときなどに使われる.(ガーベジコレクタに頼れない時以外は通常使わない)
    • public voidメソッドに付けることができる.
    • @Before や @Test で例外が出されても必ず実行されることが保証される.
  • BeforeClass
    • テストクラスの中で最初に1回だけ実行したい処理(複数のテストメソッドで共通する比較的負荷の大きい処理など)に使われる.
    • 引数をとらない public static void メソッドに付けることができる.
  • @AfterClass
  • @BeforeClass で使われたリソースを開放するときなどに使われる.(ガーベジコレクタに頼れない時以外は通常使わない)
    • public static voidメソッドに付けることができる.
    • @BeforeClass で例外が出されても必ず実行されることが保証される.
  • Ignore
    • Ignore("<コメント>")
    • テストメソッドを一時的に無効化する.
    • @Test の前に付けることができる.
    • 実行時には<コメント>が報告され,テスト結果には ignored の数が表示される.
アサーションメソッド (API)
  • staticインポート「import static org.junit.Assert.*;」を記述すると便利.
  • 適切なアサーションメソッドを選択すべき.(テストを読む人の可読性の向上)
  • よく使うもの:
    • assertTrue(boolean): パラメータがtrueであることを確認.
    • assertEquals(expected, actual): 2つのオブジェクト(プリミティブの場合はその値)が同値であることを確認.
    • assertSame(expected, actual): 2つのオブジェクトが同じインスタンスであることを確認.
    • fail(): 必ずテストを失敗させる.通るべきではないところで使用.
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class MoneyTest {

    private Money m12USD;
    private Money m14USD;
    private Money m7EUR;
    private IMoney bag1;
    
    @Before
    public void setUp() throws Exception {
        m12USD = new Money(12, "USD");
        m14USD = new Money(14, "USD");
        m7EUR  = new Money(7,  "EUR");

        bag1 = MoneyBag.create(m12USD, m7EUR);
    }

    @Test
    public void addMoneyToMoneyBag() {
        IMoney expected = MoneyBag.create(new Money(12 + 14, "USD"), m7EUR);
        IMoney actual = bag1.add(m14USD);
        assertEquals(expected, actual);
    }

    @Test
    public void addMoneyBagToMoney() {
        IMoney expected = MoneyBag.create(new Money(12 + 14, "USD"), m7EUR);
        IMoney actual = m14USD.add(bag1);
        assertEquals(expected, actual);
    }

}

テストスイート

  • 複数のテストケースを一つにまとめて同時実行.
  • 慣例:
    • 各パッケージにパッケージ内の全テストを実行するテストスイート(AllTestsという名前で)を作成
    • 複数のパッケージのテストスイートを実行するテストスイートを作成
アノテーション
  • @RunWith(<テストランナークラス名>.class)
    • テストランナーに org.junit.runners.Suite を指定する.
    • @SuiteClassesアノテーションに記述されたテストクラスのテストケースをまとめて実行
  • @SuiteClasses({<テストクラス名>.class, ...})
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runnersSuite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
pubic class AllTests{
}

参考文献

Eclipse パーフェクトマニュアルベストセレクション

Eclipse パーフェクトマニュアルベストセレクション