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

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

Mockito 一部のメソッドのみをモック化する(Java モック)

ケース

例えば、テストが不可能なメソッド(外部API接続している)のみをモック化して、その他のメソッドはそのまま動作させたい場合など。

方法

Mockito の @Spy を使うと良いらしいです。
@Mock では、全てのメソッドがモック化される。
@Spy では、一部のメソッドのみをモック化することができる。

テスト対象のクラス
public class Member {
	private PointCard pointCard;
	
	public Member() {
		this.pointCard = new PointCard();
	}

	public String getMemberNameAndPoint() {
		return pointCard.getMemberName() + "_" + pointCard.getPoint();
	}
}
モック化するクラス
public class PointCard {
	public PointCard() {
	}
	
	public String getMemberName() {
		return "hoge";
	}
	
	public long getPoint() {
		return 1000L;
	}
}
テスト
public class MemberTest {
	@Spy
	PointCard pointCardMock = new PointCard();  // 1
	
	@InjectMocks
	Member memberMock = new Member();  // 2

        @Before
	public void setup() {
          MockitoAnnotations.initMocks(this);  // 3
	}

        @Test
	public void testGetMemberNameAndPointWithSpy() {
          doReturn(7777L).when(pointCardMock).getPoint();  // 4
          assertThat(memberMock.getMemberNameAndPoint(), is("hoge_7777"));  // 5
	}
}

1. モックオブジェクト(ここでは、PointCard)を生成
2. インジェクト先(テスト対象のクラス。ここでは、Member)を指定
3. インジェクトするための初期化
4. モック(PointCard)の振る舞いを指定
5. 動作確認
getMemberName() メソッドはモック化されておらず、getPoint() メソッドのみがモック化されている。
もし、@Mock を適用していた場合、getMemberName() メソッドもモック化されるが、戻り値(振る舞い)を定義していないため、null が返却される動作となる。

所感

個人的には、@Mock と @Spy が混在して、何がモックで何がモックでないのかよく分からなくなってしまった時があって、全て @Mock で頑張っていました。
ただ、こうやって使用してみると @Spy はやはり便利に感じます。
変に混在しそうになったら、テストクラス自体を分けてあげることで整理しやすくなるかもしれません。