Mockitoでできること

Junitで使用するMockitoでいろいろ実験。 Mockitoを使用することで、任意のメソッドの挙動(返り値や例外送出)を操作することができる。
本来のテスト対象でないメソッドなどを一定の動きに制約したい時などに使う。

使用する場合はJarをダウンロードするもしくはMavenに依存関係を追加すること。

では以下にコードで例を示す。

/**
 * Mockitoを使用したテスト
 * @author User
 *
 */
public class MainStudyTest {
    @Test
    public void モックオブジェクトの生成とメソッドの戻り値定義() {
        //モックオブジェクトの作成
        List<String> mockList = Mockito.mock(List.class);
        //デフォルトでの返り値はオブジェクトならNULL、プリミティブ型ならそのデフォルト値
        assertThat(mockList.get(0), is(nullValue()));
        assertThat(mockList.get(1), is(nullValue()));
        assertThat(mockList.contains("hello"), is(false)); //booleanのデフォルト(false)となる
        assertThat(mockList.size(), is(0));//int のデフォルト(0)となる
        assertThat(mockList.indexOf("bye"), is(0));//int のデフォルト(0)となる
    }
    
    @Test
    public void メソッドの返り値の操作および例外の送出() {
        //モックオブジェクトの作成
        List<String> mockList = Mockito.mock(List.class);
        //メソッドの返り値を任意の値にする(when mockList.get(0) then return "getZero"という自然言語に近い構文になる)
        when(mockList.get(0)).thenReturn("getZero");
        assertThat(mockList.get(0), is("getZero"));
        
        //メソッドから例外送出させる
        when(mockList.get(1)).thenThrow(new IndexOutOfBoundsException());
        try {
            mockList.get(1);
            fail();
        } catch (Exception e) {
            assertThat(e, is(instanceOf(IndexOutOfBoundsException.class)));
        }
        //任意のExceptionを選択できるが、以下の例は実行時エラーになる
        //送出するExceptionに選択できるのは、そのメソッドがthrowする例外のみ
        when(mockList.get(2)).thenThrow(new FileNotFoundException());
    }
    
    @Test
    public void voidメソッドに対する挙動の操作() {
        //モックオブジェクトの作成
        List<String> mockList = Mockito.mock(List.class);
        //void型のメソッドに対する挙動の操作
        //#clear()が呼ばれた際にRuntimeExceptionをスローする
        doThrow(new RuntimeException()).when(mockList).clear();
        try {
            mockList.clear();
        } catch(Exception e) {
            assertThat(e, is(instanceOf(RuntimeException.class)));
        }
    }
    
    //
    @Test
    public void 引数の値によらず任意のメソッドの挙動を操作する() {
        //引数を特に指定せずに、メソッドの挙動のみを操作したいとき
        List<String> mockList = Mockito.mock(List.class);
        //#get()が呼ばれたら引数がいずれでも常に一定の値を返す
        when(mockList.get(anyInt())).thenReturn("hello!");
        assertThat(mockList.get(0), is("hello!"));
        assertThat(mockList.get(1), is("hello!"));
        assertThat(mockList.get(99), is("hello!")); //99とかでも大丈夫
        //いろいろあるので、適宜メソッドに対応したものを使う
        anyBoolean();
        anyByte();
        anyString();
        anyChar();
        anyCollection();
        anyDouble();
        anyList();
    }
    
    @Test
    public void モックオブジェクトの操作の検証() {
        List<String> mockList = Mockito.mock(List.class);
        mockList.clear();
        mockList.add("hello");
        mockList.add("hello");
        //モックのメソッドがどのように呼ばれたかを以下で検証する
        //#clear()が1回、add(hello)が2回、add(world)が0回呼び出されていることを検証する
        //ちなみにverifyはそのまま「検証」っていう意味の単語
        verify(mockList).clear();
        verify(mockList, times(2)).add("hello");
        verify(mockList, never()).add("world");
        //以下の検証はいずれも失敗する
        verify(mockList, times(1)).add("hello");
        verify(mockList, never()).add("hello");
    }
    
    @Test
    public void モックオブジェクトの操作の検証その2_回数を範囲指定する() {
        List<String> mockList = Mockito.mock(List.class);
        //モックのメソッドがどのように呼ばれたか
        mockList.clear();
        mockList.add("hello");
        mockList.add("hello");
        mockList.get(0);
        mockList.get(1);
        mockList.remove(1);
        verify(mockList).clear(); //#times()を指定しない場合は1回の検証
        //使用されたメソッドは以下のように最低〇回みたいな記述もできる
        verify(mockList, atLeastOnce()).remove(1); //#removeが最低1回よばれたこと
        verify(mockList, atMost(2)).add("hello"); //#add(hello)が最大でも2回まで呼ばれていること
        verify(mockList, atLeast(2)).get(anyInt());//#get()が最低でも2回呼ばれていること
    }
    
}

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)