JUnitと一緒に使うモックライブラリで個人的にMockitoを使ってたのですが、プロジェクト内の別の人はEasyMockを使っており、どのモックライブラリが使いやすいのかなと思い、3つのライブラリを使ってみました。最後に、オススメ度をつけてますが、あくまでも個人的な見解です。
環境
Java 1.7
JUnit 4.10
JMockit 1.22
Mockito 1.10.19
EasyMock 3.4
PowerMock 1.6.4
外部インターフェースをモック化することを想定し、各ライブラリを使用してJUnitを作成しました。
テスト対象とインターフェースは下記のソースとします。
public class Sample {
private CallStore store = null;
/**
* 電話番号を取得
* @param name
* @return
*/
public String getcallNumber(String name,String area) {
String number = store.getCallNumber(name);
if (number == null) {
number = "";
} else {
if ("Tykyo".equals(area)) {
number = "03-" + number;
}
}
return number;
}
}
interface CallStore {
public String getCallNumber(String name);
public String getCallArea(String area);
}
まずは、Mockitoです。
アノテーションを使うときに MockitoAnnotations.initMocks(<Class>class);
が
必要なのが残念な感じがします。(アノテーションを使わなければいいだけなんですけどね)
モックの定義は英文のように定義できるのでわかりやすいのではないでしょうか?
doReturn(これを返すよ).when(このオブジェクトの).このメソッドで
また、PowerMock + Mockitoによるprivateメソッドをモック化した場合、EclEmmaではカバレッジが測定されないため、カバレッジが必要な方は注意が必要です。
public class SampleUseMockitoTest {
@Mock
CallStore store;
@InjectMocks
Sample sut = new Sample();
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetCallNumber() {
// SetUp
Mockito.doReturn("000-1111").when(store).getCallNumber(Matchers.anyString());
String expected = "000-1111";
String name = "Tanaka";
String area = "Kanagawa";
// Test
String actual = sut.getcallNumber(name, area);
// Verify
assertThat(actual, is(expected));
}
}
続いては、EasyMock。
Mockitoとは違いアノテーションを使うときに初期化がいらないようですが、モックを有効にするためにreplay()
が必要です。
モックが増えるとたくさん指定しないといけなくなるので個人的には嫌です。
モックの定義は、Mockitoとは異なり日本語のように定義できるのでEasyMockの方が定義が理解しやすいと思います。
また、PowerMock + EasyMockによるprivateメソッドをモック化した場合、EclEmmaではカバレッジが測定されないため、カバレッジが必要な方は注意が必要です。
public class SampleUseEasyMockTest {
@Rule
public EasyMockRule mocks = new EasyMockRule(this);
@Mock
private CallStore store;
@TestSubject
private Sample sut = new Sample();
@Test
public void test() {
EasyMock.expect(store.getCallNumber(EasyMock.anyString())).andReturn("000-1111");
String expected = "000-1111";
String name = "Tanaka";
String area = "Kanagawa";
EasyMock.replay(store);
// Test
String actual = sut.getcallNumber(name, area);
// Verify
assertThat(actual, is(expected));
}
}
続いて、JMockitです。
アノテーションは初期化なしで使えます。
モック定義はブロック内でまとめて定義できるので見やすいと思います。
モックの定義も通常の定義に対してresultで期待する戻り値を記述するだけなので、特に迷うことはないと思います。(戻り値がvoidの場合は定義の仕方が変わると思います。)
また、privateメソッドをモック化した場合でも、EclEmmaでカバレッジの測定が可能なので、MockitoやEasyMockと比べてJMockitの強みだと思います。
@RunWith(JMockit.class)
public class SampleUseJMockitTest {
@Injectable
private CallStore store;
@Tested
private Sample sut = new Sample();
@Test
public void test() {
// SetUp
new Expectations() {{
store.getCallNumber(anyString); result = "000-1111";
}};
String name = "Tanaka";
String area = "Kanagawa";
String expected = "000-1111";
// Test
String actual = sut.getcallNumber(name, area);
// Verify
assertThat(actual, is(expected));
}
}
最後にオススメ度です。最初にも記述していますがあくまでも個人的な見解です。
##オススメ度
・EasyMock
オススメ度:★★☆☆☆
モック化したオブジェクトに対してreplay()
をコールしないといけない点、
モックする場合にexpect(モック定義)
で定義しなければいけない部分がマイナスだと
思います。
・Mockito
オススメ度:★★★☆☆
EasyMockと異なりreplay()
がいらないのがよい点です。
ただし、PowerMockを使用したときにカバレッジが測定できない点がマイナスです。
・JMockit
オススメ度:★★★★☆
モックをブロック内で定義でき、モック定義の複雑さはMockitoと変わらないと
思います。
privateメソッドをモック化してもカバレッジが測定できる点は非常にプラスな点だと
思います。ただし、学習コストが他のライブラリよりもかかるかと思います。
個人的な見解で、オススメ度を付けてみましたが、私自身もJMockitをあまり知らないのでこれから学んでみようと思います。学習する中でオススメ度は更新できたらと思います。(Theoriesランナーと同時に使用できるか気になる点でもあります。)