ひよっこ。

I want to…

EasyMockを使う

Posted by hikaruworld : 2008 12月 10

久々に使ったらやっぱり忘れていたのでメモしておく。

EasyMockに対して、インターフェイスを与えることで
簡単にモックテストを行えるように作られたモックを提供するためのライブラリ。
俗にいう、Service層やController層でのテストで用いられる事が多い。

実際にはSpringなどのようにDIコンテナなフレームワークを用いてインターフェイスベースで設計された
システムのテストを行う際に有用に使用することが可能。
なお、クラスによる直接の実行でもEasyMockClassExtensionを使用することでMock化することはできる。

インストール

  1. ここから最新版をダウンロードする。現時点では、2.3を使用(古っ)。
  2. 展開後、ディレクトリ直下のeasymock.jarにパスを通す。
  3. 以上。

手順

詳細に関しては、下記サンプルや同梱されているjavadocを見た方が断然分かりやすい。
が、ちょっと独特なのでテストをEasyMockを使って行う具体的な実行方法を書いておく。

  1. createMockでインターフェイスからMockオブジェクトを作成
  2. expect()メソッドを使って振る舞いを記録
  3. replay()メソッドを使って再生
  4. verify()メソッドを使って検証
  5. reset()メソッドを使って初期化

いつも思うのだけどもビデオの録画みたい。
やっぱり、このやり方は微妙になれないデス。

サンプル

TaskServiceImplのテストを行う際に、内部にインターフェイスの呼び出しTaskDaoが存在しており、
インターフェイスの実装がまだできていない場合に、TaskDaoをMockオブジェクトを使ってラップしてテストを行う方法。

  • class TaskServiceImpl
 /**
 * タスク関連サービス
 */
 public class TaskServiceImpl {
     /**
       * タスク登録時に設定されるDao層のインターフェイス
       * 今回は、このインターフェイスをラップする。
       */
     private TaskDao taskDao;
    /**
     * タスクを登録する。
     * @param userId 登録ユーザID
     * @param taskName タスク名
     * @return 登録されたタスク名の内部ID
     */
     int insertTask(int userId, String taskName) {
         // この処理をmockオブジェクトに置き換える。
         int resultId = this.taskDao.insert(task);
        
         return resultId;
     }
 }
  • テストクラス
// 処理しやすいようにstatic
import static org.easymock.EasyMock.*;

public class TaskServiceImplTest {
     /** 検査対象サービス */
     private TaskServiceImpl taskServiceImpl;
     /** Mockコントロール対象のインターフェイス */
     private TaskDao taskDao;
     /**
      * テストメソッド
      */
     public void test() {
         //検査対象を初期化
         this.taskServiceImpl = new TaskServiceImpl();

         // MockControllからインスタンスを生成
         this.taskDao = createMock(TaskDao.class); //--------------①

         // MockControllによってインスタンス化されたTaskDaoオブジェクトを
         // 検査対象に設定する。
         this.taskServiceImpl.setTaskDao(this.taskDao); //---------------②

         // -- 記録モード --
         // expectメソッドを使って、どのメソッドがどのような引数で呼ばれたときに、
        // どのような値が返却されるか指定できる。
         expect(this.taskDao.insert(task)).andReturn(1);//---------------③

         // -- 実行モード --
         // Mockによって実行させるインスタンスを実行対象として指定する。
         // これによって記録したモードを実行するようになる。
         replay(this.taskDao);//---------------④
         int i = this.taskServiceImpl.insertTask(1, "piyo");//---------------⑤

         // チェック
         // Junitと一緒に使う場合はこんな感じで。
         assertEquals(i, i);

         // -- 検証モード --
         // 記録したとおりに実行されたか確認を行う。
         // 検証モードを実行すると、記録モードで設定した通りにインスタンスが渡され、戻り値が返されたかの検証を行う。
         verify(this.taskDao);//---------------⑥

         // -- 後片付け --
         // 同一インスタンス内で再度expectするためには、初期化処理が必要。
         // これによって記録モードから設定した一連の処理が初期化され、再度記録が可能になる。
         reset(this.taskDao);//---------------⑦

     }
}
  1. Mockオブジェクトを生成する。
    this.taskDao = createMock(TaskDao.class);
    this.taskServiceImpl.setTaskDao(this.taskDao);

  2. 同上
  3. expectメソッドを使って、どのメソッドがどのような引数で呼ばれたときに、どのような値が返却されるか指定できる。
    expect(this.taskDao.insert(task)).andReturn(1);

  4. 実行対象を指定する。
    replay(this.taskDao);
    int i = this.taskServiceImpl.insertTask(1, task);

  5. 同上
  6. 検証モード
    verify(this.taskDao);

  7. 後片付け
    reset(this.taskDao);

おまけ

EasyMockClassExtensionの場合でも、privateなメソッドを実行することは不可能らしい。orz…

EasyMock Class Extension provides a built-in behavior for equals(), toString() and hashCode(). It means that you cannot record your own behavior for these methods. It is coherent with what EasyMock do. This limitation is considered to be a feature that prevents you from having to care about these methods. Final methods cannot be mocked. If called, their normal code will be executed. Private methods cannot be mocked. If called, their normal code will be executed. Remember this can occur during partial mocking. Class instantiation is performed using Objenesis. Supported JVMs are listed here. In the Advanced section, it was explained how to do partial mocking. One important thing is that private methods are never mocked. So if your method under test is calling some private methods, you will need to test them as well since you cannot mock them.

戻り値がないvoidメソッドを呼び出す場合は、以下のように直接メソッドを呼び出すだけでよい。

testDao.update();
replay(testDao);//処理を記憶

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

 
%d人のブロガーが「いいね」をつけました。