Categories: JavaJUnitMockito

【Mockito入門】SpyとMockの違い・使い分け方

この記事では@Mock@Spyの使い分け方について解説します。
テスト対象として以下のCalc2.javaSubCalc2.javaを用意し、Calc2.javaをテストするためのテストコードCalcTest2.javaを書きました。

プロダクトコード

Calc2.javaでは、SubCalc2.javaの各メソッドの戻り値を確認できるようにprint文を仕込んでいます。

Calc2.java

package products;

public class Calc2 {
	private SubCalc2 subCalc2;

	public Calc2(){
		this.subCalc2 = new SubCalc2();
	}

	public int add(){

        int x = this.subCalc2.getValA();
        System.out.println("変数x:" + x);

        int y = this.subCalc2.getValB();
        System.out.println("変数y:" + y);

        int z = this.subCalc2.getValC(x, y);
        System.out.println("変数z:" + z);

        return x + y + z;
	}
}

SubCalc2.javagetValC(int x, int y)は完成しているとみなします。

SubCalc2.java

package products;

public class SubCalc2 {
    public int getValA(){
    	// まだ開発途中
        return 1;
    }
    public int getValB(){
    	// まだ開発途中
    	return 1;
    }
    public int getValC(int x, int y){
        // このメソッドは完成!
    	return x * y;
    }
}

テストコード

SubCalc2.javagetValC(int x, int y)は完成しているのでモック化しません。
モック化するのはgetValA()getValB()のみとします。

CalcTest2.java

package products;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;

public class CalcTest2 {

	@InjectMocks
	private Calc2 calc2;

	@Mock
	private SubCalc2 subCalc2;

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

	@Test
	public void test01(){

		// SubCalcクラスの「getValA」メソッドをモックし、実行された場合は3を返す。
        Mockito.doReturn(3).when(subCalc2).getValA();

        // SubCalcクラスの「getValB」メソッドをモックし、実行された場合は4を返す。
        Mockito.doReturn(4).when(subCalc2).getValB();

        // 実行して結果を受け取る
		int actual = calc2.add();

		// 期待値の設定
		int expected = 19;

		// 検証
		assertEquals(expected,actual);
	}

	@Test
	public void test02(){
		// ここは空振りするけど、initMocksは実行される。
	}
}

Junit実行結果

実行結果は以下のとおりです。
calc2.add()getValA()getValB()getValC(int x, int y)の合計を返却します。
ですので、3+4+12=19となるはずですが、以下の実行結果を見ると7が返ってきているので失敗です。

java.lang.AssertionError: expected:<19> but was:<7>

コンソール

コンソールを見てみると変数zの値が0です。
つまりgetValC(int x, int y)がうまく動作していないことが判ります。

変数x:3
変数y:4
変数z:0

修正箇所

テストコードの中の@Mockアノテーションを@Spyアノテーションに置き換えます。
修正前

// 修正前
@Mock
private SubCalc2 subCalc2;

修正後

// 修正後(「import org.mockito.Spy;」も必要)
@Spy
private SubCalc2 subCalc2;

上記修正後、テストコードを再実行すれば無事グリーンになるはずです。コンソール上も以下のとおり、変数zの値が取得できています。

変数x:3
変数y:4
変数z:12

解説

@Mockアノテーション

モック化していないメソッドが呼び出されたとき、処理が空振りします。

@Spyアノテーション

モック化していないメソッドが呼び出されたとき、記述したとおりに実行されます。

@Spyアノテーションと@Mockアノテーションの違い

テストコードの中で、モック化していない処理をそのまま実行させたいときは@Spyアノテーションを使うのが良いということです。


以上で記事の解説はお終い!

もっとJavaやSpringを勉強したい方にはUdemyがオススメ!同僚に差をつけよう!

issiki_wp