EasyMockを使ってみた
ユニットテストを行うときに困るのが
HttpServletRequest等のサーバなどで生成されるインスタンスを
引数としているメソッドのテストです。
そんなときはモックという擬似オブジェクトを
利用したテストを行うのが一般的です。
私もJUnitでテストを行う為にモックを
利用しようと思ったのですが、
昔利用していたmockobjectというライブラリが無くなっていました。(年を感じます;_;)
今はEasyMockやjMockといったライブラリが利用されているようです。
ということで今回、EasyMockを初めて使ってみました。以下、使い方です。
http://www.easymock.org/index.html
(バージョンは2.4を使用)
まず最初にダウンロードしたら
easymock.jarをクラスパスに通します。
次に、
import static org.easymock.EasyMock.*
をテストソースにインポート宣言します。
以上でテスト準備終了です。
それでは、HttpServletRequestのスタブを作成して
テストを行ってみます。
//HttpServletRequestのモックを生成 HttpServletRequest mock = createMock(HttpServletRequest.class); // モックオブジェクトに振る舞いを記憶 expect(mock.getParameter("hogehoge")).andStubReturn("fugafuga"); // モックオブジェクトを再生モードに切り替え replay(mock); // テスト実施 assertEquals("結果", Hoge.getResult(mock));
EasyMockの挙動は少し変わっていて、以下のような流れになります。
モック生成 -> 処理の記録 -> 再生モードに切り替え -> 再生
と、いきなりMockの利用は出来ず、必ず再生モードに切り替える必要があります。
JMockの場合は、わざわざ再生モードに切り替える必要はなく、
処理の記録には文字列でメソッドを指定します。
私は、癖はありますが、Eclipse等のIDEの補完機能が利用できる
EasyMockのアプローチは結構ありだと思います。
上記は、単純なスタブとしての利用でしたが今度は
モックとしてオブジェクトのメソッドが正しく呼び出されたかの
確認も行ってみます。
//HttpServletRequestのモックを生成 HttpServletRequest mock = createMock(HttpServletRequest.class); // モックオブジェクトに振る舞いを記憶 expect(mock.getParameter("hogehoge")).andReturn("fugafuga"); // モックオブジェクトを再生モードに切り替え replay(mock); // テスト実施 assertEquals("結果", Hoge.getResult(mock)); // モックオブジェクトが振る舞い通りに呼ばれたか確認 verify(mock);
andStubReturnをandReturnに変更し、最後にverifyを追加しました。
これでHoge.getResult内でmockのgetParameterが呼ばれたかを確認して
呼ばれなかった場合はverifyでエラーとなります。
上記は処理内部でgetParameterを1回呼び出すテストになりますが、
複数呼び出す指定や曖昧な呼び出しなども表現できます。
振る舞いの記憶いろいろ
1回呼び出し
//返り値なし mock.setAttribute("foo", "bar"); //返り値あり expect(mock.getParameter("hogehoge")).andReturn("fugafuga");
3回呼び出し
//返り値なし mock.setAttribute("foo", "bar"); expectLastCall().times(3); //返り値あり expect(mock.getParameter("hogehoge")).andReturn("fugafuga").times(3);
少なくとも1回呼び出し
expect(mock.getParameter("hogehoge")).andReturn("fugafuga").atLeastOnce();
任意の回数呼出し
expect(mock.getParameter("hogehoge")).andReturn("fugafuga").anyTimes(); //以下と同じ? expect(mock.getParameter("hogehoge")).andStubReturn("fugafuga");
Exceptionをスロー
expect(mock.getParameter("hogehoge")).andThrow(new Exception());
引数のチェック
//booleanであればOK expect(mock.getSession(anyBoolean())).andReturn(null); //指定されたクラスであればOK expect(mock.getParameter(isA(String.class))).andReturn("fugafuga"); //配列のチェック String[] strings = new String[]{"foo", "bar"}; mock.setArray(aryEq(strings));
メソッド呼び出し順序のテスト
//メソッドの呼び出し順序をチェックするモックを生成 HttpServletRequest mock = createStrictMock(HttpServletRequest.class);
モックの再利用
//モックのリセット(記憶モードに戻る) reset(mock);
このようなツールを利用して
少しでもテストの自動化を行うことで
品質の維持が出来るのではないかなと思います。