社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

初 JMockit の感想

JUnit で使えるモックのライブラリには、mockito, jmockit, easymock などがあります。
個人的には mockito しか使ったことがなかったのですが、jmockit がよく使われているらしいので、試してみました。

具体的な使い方などは既に多くの記事が存在しますので、ここには書かないです。
※個人的な感想

1.テスト対象のクラス
Hoge.class -> テストの対象とする主クラス。
Foo.class -> Hoge.class から呼び出されるクラス。

どちらも、文字列を返すだけのシンプルなメソッドしか用意していません。
そして実際のテストクラスです。

テストコード1

テストコード2


2.クラス変数として mock を定義すると、全テストメソッドに適用される

// To specify as class value, every test can get the mock.
@Mocked private Hoge hogeMock;
	
@Test
public void testLocalValueBecomeMockFromClassValue() {
	Hoge hoge = new Hoge();
	assertThat(hoge.methodHoge(), nullValue());
}

@Test
public void testLocalValueBecomeMockFromClassValue2() {
	assertThat(hogeMock.methodHoge(), nullValue());
}

シンプルなテストクラスに対しては便利かもしれないけど、意図しない mock が適用されてしまう可能性がある。
次の例のように、各テストクラス毎に mock を渡してあげる方がよいと思います。

@Test
public void testLocalValueBecomeMockFromArg(@Mocked Hoge hogeMock) {
	Hoge hoge = new Hoge();
	assertThat(hoge.methodHoge(), nullValue());
}

3.特定のインプットに対する戻り値をテストするなら、Expectations。不特定のインプットに対しては NonStrictExpectations。
Expectations

@Test
public void testExpectationsWithReturnValue() {
	new Expectations() {{
		hogeMock.methodHoge(); result = "called without arguments.";
		hogeMock.methodHoge("hoge"); result = "called with arguments";
	}};
	
	assertThat(hogeMock.methodHoge(), is("called without arguments."));
	assertThat(hogeMock.methodHoge("hoge"), is("called with arguments"));
}

Expectations を使う場合は、Expectations 内で定義した順番と、assert の順番を揃える必要がある点に注意ですね。

NonStrictExpectations

@Test
public void testNonStrictExpectations() {
	new NonStrictExpectations() {{
		hogeMock.methodHoge(anyString); result = "stub returns value";
	}};
	
	// To specify "anyString", always returns same value.
	assertThat(hogeMock.methodHoge("hoge"), is("stub returns value"));
	assertThat(hogeMock.methodHoge("mock"), is("stub returns value"));
	assertThat(hogeMock.methodHoge("always"), is("stub returns value"));
}

どんな文字列でもの意味である anyString とか便利ですね。
スタブとして使う部品が入力値に依らず、常に同じ値を返して良いのであれば、これは使えますね。

4.Injectable を使えば、テスト対象クラスのクラス変数も簡単に mock にできる

@Tested private Hoge hogeTested;
@Injectable private Foo foo;

@Test
public void testHogeMethodHasIntValue() {
	final String abcString = "abc";
	new Expectations() {{
		foo.methodString(abcString); result = "return from methodString";
	}};
	
	assertThat(hogeTested.methodHoge(abcString), is("return from methodString"));
}

Injectable で定義されたクラス変数は Tested で定義されたクラス内で mock になる。
戻り値も自由自在に定義できる。すごく便利ですね。

5.感想
初めて JMockit 使ってみましたが、簡単に mock が作れて戻り値の定義も出来るので非常に便利だと思います。
慣れてくれば楽に書けるようになりそうです。
ただあまり乱用すると、可読性が落ちそうですし、mock 全てに対して言えることですが、 mock 化すべき対象は API や外部ストレージからの応答など、可変性があるものに限定したいですね。