Seasar DI Container with AOP

EasyMockサポート

目次

概要

EasyMockはモックを利用したテストのためのフレームワークです.モックの振る舞いを設定するのにメソッド名などを文字列で指定するのではなく,インタフェースのメソッド呼び出しで指定することができるため,タイプミスを防げる・エディタの入力補完を利用できる・リファクタリングに追従しやすいなどのメリットがあります.

Seasar2のEasyMockサポートを使うとEasyMockを利用するための定型的なコードの記述を減少することができるため,モックを使ったテストがより簡単になります.

前提条件

  • Seasar2ではEasyMock2.4およびEasyMock Class Extension2.4をサポートしています.
    • EasyMock単体でも利用できます.
    • EasyMock Class Extensionを使用するにはCGLIBも必要です.
  • EasyMock2.4はJava5で導入されたGenericsを使用しているため,J2SE1.4では利用できません.
  • Seasar2のEasyMockサポートを利用するにはS2-Tigerが必要です.

EasyMockを使ったテストの流れ

EasyMockを使ったテストの流れを以下に示します.

  • モックを作成する
  • モックの振る舞いを記録する (record)
  • モックとのインタラクションを再現する (replay)
  • モックとのインタラクションを検証する (verify)

モックとインタラクションする「replay」モードのコードが本来のテストコードになります.

Seasar2のEasyMockサポートもこの流れに沿ったテストを支援します.

テストクラス

Seasar2のEasyMockサポートはJUnit3とJUnit4の両方をサポートします.

JUnit3

JUnit3でEasyMockを使ったテストを行うために,次の二つの抽象クラスが提供されています.

org.seasar.framework.unit.EasyMockTestCase
junit.framework.TestCaseの派生クラスで,S2コンテナを利用しない場合に使用します.
org.seasar.framework.unit.S2TigerTestCase
org.seasar.framework.unit.S2TestCaseの派生クラスで,S2コンテナを利用する場合に使用します.
public class HogeTest extends S2TigerTestCase {
    ・・・
}

JUnit4

JUnit4でEasyMockを使ったテストを行うには,S2JUnit4のRunnerを使用します.

@RunWith(Seasar2.class)
public class HogeTest {
    ・・・
}

モックの作成

アノテーションによるモックの作成

モックを作成するにはテストクラスのフィールドに@EasyMockアノテーションを指定します.

public class HogeTest extends S2TigerTestCase {
    @EasyMock
    private Foo foo;
    ・・・
}

@EasyMockアノテーションが付けられたフィールドの型からモックが作成され,フィールドに設定されます.

モックの種類を指定する

モックの種類を指定することもできます.それには@EasyMockアノテーションのvalue要素で列挙型EasyMockTypeの定数を指定します.

public class HogeTest extends S2TigerTestCase {
    @EasyMock(EasyMockType.STRICT)
    private Foo foo;
    ・・・
}

列挙型EasyMockTypeには以下の定数があります.

DEFAULT
デフォルトモードのモックを作成します.
デフォルトモードのモックは指定されていないメソッドが呼び出されると例外をスローしますが,メソッドの呼び出し順は無視します.
STRICT
Strictモードのモックを作成します.
Strictモードのモックは指定されていないメソッドが呼び出されると例外をスローします.指定されたメソッドであっても,指定された通りの順でメソッドが呼び出されないと例外をスローします.
NICE
Niceモードのモックを作成します.Niceモードのモックは指定されていないメソッド呼び出しが行われても例外をスローしません.

モックをS2コンテナに登録する

S2TigerTestCaseのサブクラスでは,作成されたモックをS2コンテナに登録することができます.それには@EasyMockアノテーションのregister要素でtrueを指定します.

public class HogeTest extends S2TigerTestCase {
    @EasyMock(register=true)
    private Foo foo;
   ・・・
}

モックのコンポーネント名はフィールド名となります.

モックの登録はS2コンテナの初期化前に行われるため,登録されたモックは他のコンポーネントにDIされる対象となります.モックに対するDIは行われません.

明示的にモックを作成する

JUnit3では,@EasyMockアノテーションを使わず,setUp()メソッドまたはsetUpXxx()メソッド (S2TigerTestCaseのサブクラスのみ) の中で明示的にモックを作成することもできます.それには以下のメソッドを使用します.

  • T createMock(Class<T>)
  • T createStrictMock(Class<T>)
  • T createNiceMock(Class<T>)
public class HogeTest extends S2TigerTestCase {
    private Foo foo;

    protected void setUp() throws Exception {
        super.setUp();
        foo = createMock(Foo.class);
    }
    ・・・
}

モックの振る舞いを記録する

モックの振る舞いを記録するには,"record"メソッドを使用します.

JUnit3

"record"メソッドはテストメソッドの接頭辞"test"を"record"にした名前を持つpublicなインスタンスメソッドです.

public class HogeTest extends S2TigerTestCase {
    public void recordXxx() throws Exception {
        ・・・
    }

    public void testXxx() throws Exception {
        ・・・
    }
}

testXxx()メソッドの実行前に,対応するrecordXxx()メソッドが実行されます.テストメソッドがtest()の場合は対応する"record"メソッドは実行されません.

JUnit4

"record"メソッドはテストメソッドに接頭辞"record"をつけた名前を持つpublicなインスタンスメソッドです.

@RunWith(Seasar.class)
public class HogeTest {
    public void recordXxx() throws Exception {
        ・・・
    }

    public void xxx() throws Exception {
        ・・・
    }
}

xxx()メソッドの実行前に,対応するrecordXxx()メソッドが実行されます.

JUnit3とJUnit4共通

"record"メソッド内ではEasyMockの機能を使用してモックの振る舞いを記録します.

    public void recordXxx() throws Exception {
        expect(foo.someMethod(100)).andReturn(200);
    }
expectメソッドはorg.easymock.EasyMockのstaticメソッドです。この例ではstatic import機能を利用して呼び出しています.

モックとのインタラクションを再現する

モックとのインタラクションを再現するには通常のテストメソッドを使用します.

作成済みのモックは,テストメソッドの実行前に"replay"モードに設定されます.

    public void testXxx() throws Exception {
        assertEquals(200, foo.someMethod(100));
    }

モックとのインタラクションを検証する

テストメソッドの実行が正常に終了すると自動的にモックとのインタラクションが検証されます.