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

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

JMockito 引数に応じて返す値を変化させる(Java モック)

これの JMockito 版です。
blueskyarea.hatenablog.com

テストコード(JUnit)
@RunWith(JMockit.class)
public class BirthMonthTest {
	// Without mock
	@Test
	public void testGetBirthStoneWithoutMock() {
		BirthMonth birthMonth = new BirthMonth(2);
		assertThat(birthMonth.getBirthStone(2), is(nullValue()));
		assertThat(birthMonth.getBirthStone(7), is(nullValue()));
		assertThat(birthMonth.getBirthStone(11), is(nullValue()));
	}
	
	// With mock
	@Test
	public void testGetBirthStoneWithMock(@Mocked BirthMonth birthMonth) {
	    new NonStrictExpectations() {
              {
            	birthMonth.getBirthStone(2);
            	result = "amethyst";
            	birthMonth.getBirthStone(7);
            	result = "ruby";
            	birthMonth.getBirthStone(11);
            	result = "topaz";
            	birthMonth.getBirthStone(anyInt);
            	result = "not found";
              }
	  };
		
          // exception if not "NonStrictExpectations".
	  assertThat(birthMonth.getBirthStone(5), is("not found"));

	  assertThat(birthMonth.getBirthStone(2), is("amethyst"));
	  assertThat(birthMonth.getBirthStone(7), is("ruby"));
	  assertThat(birthMonth.getBirthStone(11), is("topaz"));
	  assertThat(birthMonth.getBirthStone(20), is("not found"));
		
	  // exception if not "NonStrictExpectations".
	  assertThat(birthMonth.getBirthStone(30), is("not found"));
	}
}

Expectations を使用した場合、定義した振る舞いの順番どおりに、そのメソッドが呼ばれることが期待される。
この例では、まず最初に 2 が引数として与えられた場合の振る舞いが定義されている。
ただ、assertThat では最初に 5 が引数として与えられることになっているため、この時点でエラーになる(expect 2, but 5)。
また、最後の assertThat では 30 を引数として与えているが、定義した振る舞いの anyInt は、その前の引数 20 に対して適用されるため(使用済みのような扱い)、30 の場合の振る舞いが定義していないということでエラーになる。
いずれの場合も以下のエラー。

UnexpectedInvocation: Unexpected invocation of:

NonStrictExpectations を使用してあげることで、この辺りの制約がゆるくなり、定義した振る舞いの数が呼び出しの数よりも少なかったとしても、anyInt で定義した振る舞いが適用されるか、もし anyInt を定義していなければ、null(初期値) が返却されるような動作になる。

機能的には問題ないと思うのですが、この辺りについては Mockito の方が若干分かり易い(書き方)気がします。

Mockito の場合。

when(birthMonth.getBirthStone(2)).thenReturn("amethyst");

JMockito でも、無理やり一行で書けますが。。

birthMonth.getBirthStone(2); result = "amethyst";