JMockit の Mock 化する方法あれこれ

JMockit で java.util.Calendar のメソッドを Mock 化する - kntmr-blog

これの続き。

以下、テスト対象クラスとして単純に文字列を連結して返すだけのクラスを用意。

public class FooService {
    BarService barService;
    public String execute(String arg) {
        return "Foo" + barService.execute(arg);
    }
}

public class BarService {
    public String execute(String arg) {
        return "Bar" + arg;
    }
}

JMockit の Expectations で Mock 化する

モック化は MockUp<T> を使う方法以外に、Expectations を使う方法がある。

FooService#execute(String) をテストする場合。

public class FooServiceTest {
    @Tested
    FooService sut;
    @Injectable
    BarService barService;
    @Test
    public void test() {
        final String expected = "FooBARBAZ";
        new Expectations() {
            {
                barService.execute(anyString); result = "BARBAZ"; times = 1; // モックの挙動と呼出しの検証
            }
        };
        String actual = sut.execute("dummy");
        assertThat(actual, is(expected));
    }
}

Expectations はモックの挙動を定義するだけではなく、メソッド呼出しを検証することができる。
上記は times = 1BarService#execute(String) が1回だけ呼ばれることを検証する。

Verifications を使うと検証の部分を Expectations から分離することができる。

public class FooServiceTest {
    @Tested
    FooService sut;
    @Injectable
    BarService barService;
    @Test
    public void test() {
        final String expected = "FooBARBAZ";
        new Expectations() {
            {
                barService.execute(anyString); result = "BARBAZ"; // モックの挙動を定義
            }
        };
        String actual = sut.execute("dummy");
        assertThat(actual, is(expected));
        new Verifications() {
            {
                barService.execute(anyString); times = 1; // 呼出しの検証
            }
        };
    }
}

モックに渡した値を検証する場合。

public class FooServiceTest {
    @Tested
    FooService sut;
    @Injectable
    BarService barService;
    @Test
    public void test() {
        sut.execute("hogehoge");
        new Verifications() {
            {
                List<String> arg = new ArrayList<String>();
                barService.execute(withCapture(arg)); times = 1;
                assertThat(arg.get(0), is("hogehoge"));
            }
        };
    }
}

withCapture でモックに渡した値をチェックすることができる。

JMockit で private メソッドを Mock 化する

以下、文字列の連結部分を private メソッドに切り出しただけのクラス。

public class FooService {
    public String execute(String arg) {
        return executeInternal(arg);
    }
    private String executeInternal(String arg) {
        return "Foo" + arg;
    }
}

FooService#executeInternal(String) をテストする場合。

public class FooServiceTest {
    @Tested
    FooService sut;
    @Test
    public void test() {
        final String expected = "FooBar";
        String actual = Deencapsulation.invoke(sut, "executeInternal", "Bar");
        assertThat(actual, is(expected));
    }
}

Deencapsulation#invoke(Object, String, Object...) にテスト対象クラスとメソッド名、パラメータを渡して private メソッドを実行する。