初 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 や外部ストレージからの応答など、可変性があるものに限定したいですね。