JMockitを使用した単体テスト5

一部分だけモックにする

オブジェクトのうち、いくつかのメソッドのみモックにし、それ以外は実際の処理を行いたい場合、

  • Static partial mocking
  • Dynamic partial mocking

の2通りの方法があります。


以下のテスト対象クラスのテストクラスを作成してみます。

テスト対象

public class Dice {

    public int play1() {
        return new Random(System.currentTimeMillis()).nextInt(6) + 1;
    }

    // テスト対象のメソッド
    public int play2(final int n) {
        int max = 0;
        for (int i = 0; i < n; i++) {
            int value = play1();  // (a) ここでモックを使う
            max = Math.max(max, value);
        }
        return max;
    }
}

play2はplay1を実行するので、試験を行う場合は、play1はモック、play2は実際の処理でなければなりません。今までの方法だと、Diceをモックにすると双方モックになってしまって試験できません。

Static partial mocking

Static partial mockingのテストクラスは以下の通りです。

テストクラス

    @Test
    public void testPlay2_Static() {
        final int n = 3;
        new Expectations() {
            // (1) Dice#play1のみモックとし、それ以外のメソッドは実処理を行う
            @Mocked(methods = {"play1"})
            Dice dice;
            {
                dice.play1();
                // (2) play1が呼ばれる毎に順番に値を返す
                returns(3, 5, 2);
            }
        };

        final Dice dice = new Dice();
        int result = dice.play2(n);
        
        assertEquals(5, result);
    }

(1)のように@Mockedのmethodパラメータのモックにするメソッド名を文字列で指定します。メソッドの指定にはいくつかのルールがあります。

  1. 複数メソッド指定する場合は","で区切る。
  2. コンストラクタの場合は"()"を指定する。
  3. メソッドがオーバーロードされているときは、"play1(int)"のように引数を指定する。
  4. setValue(), getvalue()の2つをモックにする場合は、"[sg]etValue"のように指定可能。
Dynamic partial mocking

Static dynamic mockingでは、モックにするメソッドを文字列で指定するため、メソッド名を変更した場合にIDEリファクタリングで自動的に変更されません。この問題を解決するのがDynamic partial mockingです。

テストクラスは以下の通りです。

テストクラス

    @Test
    public void testPlay2_Dynamic() {
        final Dice dice = new Dice();
        final int n = 5;
        // モックにするオブジェクトを指定する。複数指定も可。
        new Expectations(dice) {

            {
                dice.play1();
                returns(3, 2, 1, 5, 2);
            }
        };

        int result = dice.play2(n);

        assertEquals(5, result);
    }

上記のように、new Expectations()の引数にモックにするオブジェクトかクラスを指定すると、そのブロック内で呼ばれてるメソッドのみがモックになります。