ThrowableTest

概要

ユニットテストでカバレッジを100%に近づけようとする場合、 通常では例外がスローされないようなコードのテストで苦労されていませんか? ThrowableTestは任意のクラスの任意のメソッドで指定した例外をスローさせるユニットテストユーティリティです。

インストール

Javaのクラスパスに下記のJarファイルを追加します。 ThrowableTestRunnerを使用しない場合は asm-3.1.jar と asm-commons-3.1.jarは不要です。 また注釈を使用するため、java5以降およびJUnit3.8以降が必須となります。

使用法

使用方法として独自のJUnitランナーを使用する場合とプロキシを使用する場合の二つの方法があります。

JUnitランナーによるテストクラスのサンプルを以下に示します。

    @RunWith(ThrowableTestRunner.class)       // ThrowableTestRunnerをJUnitランナーに指定
    public class HogehogeTest {
        @Test(expected = SQLException.class)  // SQLExceptionがスローされるとテスト成功
        @Throw (
            targetClass = Connection.class,        // 対象となるクラス、インタフェース
            methodName = "close",                  // 例外をスローするメソッド
            exceptionClass = SQLException.class,   // スローする例外クラス
            message = "SQL例外のテストです。"         // 例外にセットされるメッセージ(省略可)
        )
        public void testSomeMethod() throws Exception {
            // テスト処理
            // targetClassおよびそのサブクラス、インタフェースの場合は
            // そのインタフェースを実装するクラスのオブジェクトで、
            // methodNameで指定した名称のメソッドが呼び出された場合に
            // exceptionClassの例外がスローされる
        }
    }
        
o instanceof targetClass がtrueとなるオブジェクトで methodNameという名称のメソッドの呼出しがあった場合に例外がスローされます。
targetClassにはインタフェースだけではなく通常のクラスも指定可能ですが、 java.*といったJavaの基本的なクラスはチェックコードの埋め込みができないため、 このようなクラスを指定しても例外はスローされません。
またテストメソッド実行時にコンテキストクラスローダを変更する都合により メソッド開始以前にインスタンス化されたオブジェクトを参照することができません。 @Before で注釈されたセットアップメソッドで作成したオブジェクトが使用できないのは不便かもしれませんが、 テストメソッドの先頭でセットアップメソッドを呼ぶようにしてください。

プロキシを使用する場合はtargetClassはインタフェースでなければならず、 対象となるオブジェクトのProxyを作成してセットしなくてはならない (対象オブジェクトがフレームワークに埋め込まれているとなかなか難しいですね) という制約はありますが、 Java基本クラスを指定できるのと対象オブジェクトを特定できるという利点があります。
プロキシを使用するテストクラスのサンプルを以下に示します。
    public class HogehogeTest {
        @Test(expected = IndexOutOfBoundsException.class)      // IndexOutOfBoundsExceptionがスローされるとテスト成功
        @Throw (
            targetClass = List.class,                          // 対象となるインタフェース
            methodName = "get",                                // 例外をスローするメソッド
            exceptionClass = IndexOutOfBoundsException.class,  // スローする例外クラス
            message = "インデックス範囲外のテストです。"            // 例外にセットされるメッセージ(省略可)
        )
        public void testSomeMethod() throws Exception {
            List xxList = ....
            xxList = ThrowableTestProxy.newInstance(xxList);
            // テスト処理
        }
    }
        
上記の例ではテストメソッドに直接記述してありますが、 Thow注釈はスタックから検索しますので テストメソッドから同一スレッドで直接的、間接的に呼ばれる場所であれば 別のメソッドでも別のクラスでもプロキシを作成できます。 セットアップメソッドなど、テストメソッド実行前にプロキシを作成する場合はThrow注釈を参照できないため、 ThrowableTestProxy.newInstance(T realObj, java.lang.Class<T> interfaceType) で第二引数にインタフェースを指定してください。 JUnitランナーとしてThrowableTestRunnerを指定しなければ コンテキストクラスローダを変更しませんので セットアップメソッドで初期化された変数の参照も可能です。

ダウンロード

API Doc

お問い合わせ
質問、バグの報告等はjohns@air.linkclub.or.jp 望月までお願いします。