JUnitのテストを行う際、Mock化したメソッドの戻り値がvoid型で、Mock化したメソッドが呼ばれたかどうかわからない場合がある。このような場合に、Mock化したメソッドの呼出回数や引数を取得することで、Mock化したメソッドの呼出確認が行える。
今回は、テーブル更新を行う箇所をMock化したメソッドの呼出回数や引数を取得してみたので、そのサンプルプログラムを共有する。
前提条件
下記記事の実装が完了していること。

サンプルプログラムの内容
作成したサンプルプログラムの構成は以下の通り。
 
 なお、上記の赤枠のうち、「DemoServiceImplTest2.java」が今回新規で作成したプログラムとなる。

「DemoServiceImpl.java」は、前提条件の記事と変更していない。下記ソースでは、今回テスト対象とするcreateOrUpdateメソッドに関する部分のみを記載している。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.BindingResult;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Service
public class DemoServiceImpl implements DemoService{
    /**
     * ユーザーデータテーブル(user_data)へアクセスするマッパー
     */
    @Autowired
    private UserDataMapper mapper;
    /**
     * {@inheritDoc}
     */
    @Override
    @Transactional(readOnly = false)
    public void createOrUpdate(DemoForm demoForm){
        //更新・追加処理を行うエンティティを生成
        UserData userData = getUserData(demoForm);
        //追加・更新処理
        if(demoForm.getId() == null){
            userData.setId(mapper.findMaxId() + 1);
            mapper.create(userData);
        }else{
            mapper.update(userData);
        }
    }
    /**
     * UserDataオブジェクトに引数のフォームの各値を設定する
     * @param demoForm DemoFormオブジェクト
     * @return ユーザーデータ
     */
    private UserData getUserData(DemoForm demoForm){
        UserData userData = new UserData();
        if(!DateCheckUtil.isEmpty(demoForm.getId())){
            userData.setId(Long.valueOf(demoForm.getId()));
        }
        userData.setName(demoForm.getName());
        userData.setBirthY(Integer.valueOf(demoForm.getBirthYear()));
        userData.setBirthM(Integer.valueOf(demoForm.getBirthMonth()));
        userData.setBirthD(Integer.valueOf(demoForm.getBirthDay()));
        userData.setSex(demoForm.getSex());
        userData.setSex_value(demoForm.getSex_value());
        return userData;
    }
}
さらに、今回作成したJUnitのプログラム「DemoServiceImplTest2.java」の内容は以下の通り。
package com.example.demo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.time.LocalDate;
import java.util.List;
import static org.mockito.Mockito.*;
import static org.junit.Assert.assertEquals;
public class DemoServiceImplTest2 {
    /**
     * テスト対象のクラス
     * (今回はSpring Bootを利用しないため、Serviceではなく
     *  ServiceImplを対象クラスに指定している)
     */
    @InjectMocks
    private DemoServiceImpl demoServiceImpl;
    /**
     * テスト対象のクラス内で呼ばれるクラスのMockオブジェクト
     */
    @Mock
    private UserDataMapper mapper;
    /**
     * 前処理(各テストケースを実行する前に行われる処理)
     */
    @Before
    public void init() {
        //@Mockアノテーションのモックオブジェクトを初期化
        //これを実行しないと@Mockアノテーション、@InjectMocksを付与した
        //Mockオブジェクトが利用できない
        MockitoAnnotations.initMocks(this);
        //Mockの設定
        //mapper.findMaxId()メソッドを実行した際の戻り値をここで設定
        when(mapper.findMaxId()).thenReturn(2L);
    }
    /**
     * DemoServiceImplクラスのcreateOrUpdateForAddメソッド(追加時)の確認
     */
    @Test
    public void testCreateOrUpdateForAdd(){
        //追加処理を行う場合の、テスト対象メソッドの引数を生成
        DemoForm demoFormAdd = makeDemoForm(null, "テスト プリン3"
                , LocalDate.of(2014, 4, 20), SexEnum.MAN);
        //テスト対象メソッドの実行
        demoServiceImpl.createOrUpdate(demoFormAdd);
        System.out.println("*** demoServiceImpl.createOrUpdateForAdd"
                + "(DemoForm(追加用))の実行結果 ***");
        //テスト対象メソッドを実行した結果、mapper.findMaxId()が1回呼ばれたことを確認
        verify(mapper, times(1)).findMaxId();
        System.out.println("mapper.findMaxId()は1回呼ばれました");
        //テスト対象メソッドを実行した結果、mapper.create(UserData)が
        //1回呼ばれたことを確認
        ArgumentCaptor<UserData> userDataCaptor
                = ArgumentCaptor.forClass(UserData.class);
        verify(mapper, times(1))
                .create(userDataCaptor.capture());
        System.out.println("mapper.create(UserData)は1回呼ばれました");
        //mapper.create(UserData)を呼び出した際の引数が想定通りであることを確認
        List<UserData> listUserData = userDataCaptor.getAllValues();
        assertEquals(1, listUserData.size());
        UserData expectUserData = makeUserData(3L, "テスト プリン3"
                , LocalDate.of(2014, 4, 20), SexEnum.MAN);
        assertEquals(expectUserData.toString(), listUserData.get(0).toString());
        System.out.println("mapper.create(UserData)の引数 : "
                + listUserData.get(0).toString());
        //テスト対象メソッドを実行した結果、mapper.update(UserData)は
        //呼ばれないことを確認
        //any()は任意の引数を表す
        verify(mapper, times(0)).update(any());
        System.out.println("mapper.update(UserData)は呼ばれませんでした");
        System.out.println();
    }
    /**
     * DemoServiceImplクラスのcreateOrUpdateForAddメソッド(更新時)の確認
     */
    @Test
    public void testCreateOrUpdateForUpdate(){
        //更新処理を行う場合の、テスト対象メソッドの引数を生成
        DemoForm demoFormUpd = makeDemoForm(2L, "テスト プリン2"
                , LocalDate.of(2013, 3, 19), SexEnum.WOMAN);
        //テスト対象メソッドの実行
        demoServiceImpl.createOrUpdate(demoFormUpd);
        System.out.println("*** demoServiceImpl.createOrUpdateForAdd"
                + "(DemoForm(更新用))の実行結果 ***");
        //テスト対象メソッドを実行した結果、mapper.findMaxId()が呼ばれないことを確認
        verify(mapper, times(0)).findMaxId();
        System.out.println("mapper.findMaxId()は呼ばれませんでした");
        //テスト対象メソッドを実行した結果、mapper.create(UserData)が
        //呼ばれないことを確認
        verify(mapper, times(0)).create(any());
        System.out.println("mapper.create(UserData)は呼ばれませんでした");
        //テスト対象メソッドを実行した結果、mapper.update(UserData)が
        //1回呼ばれたことを確認
        ArgumentCaptor<UserData> userDataCaptor
                = ArgumentCaptor.forClass(UserData.class);
        verify(mapper, times(1))
                .update(userDataCaptor.capture());
        System.out.println("mapper.update(UserData)は1回呼ばれました");
        //mapper.update(UserData)を呼び出した際の引数が想定通りであることを確認
        List<UserData> listUserData = userDataCaptor.getAllValues();
        assertEquals(1, listUserData.size());
        UserData expectUserData = makeUserData(2L, "テスト プリン2"
                , LocalDate.of(2013, 3, 19), SexEnum.WOMAN);
        assertEquals(expectUserData.toString(), listUserData.get(0).toString());
        System.out.println("mapper.update(UserData)の引数 : "
                + listUserData.get(0).toString());
        System.out.println();
    }
    /**
     * ユーザーデータを生成する
     * @param id ID
     * @param name 名前
     * @param birthDay 生年月日
     * @param sexEnum 性別Enum
     * @return ユーザーデータ
     */
    private UserData makeUserData(Long id, String name, LocalDate birthDay
                                , SexEnum sexEnum){
        UserData userData = new UserData();
        if(id != null){
            userData.setId(id);
        }
        userData.setName(name);
        if(birthDay != null){
            userData.setBirthY(birthDay.getYear());
            userData.setBirthM(birthDay.getMonthValue());
            userData.setBirthD(birthDay.getDayOfMonth());
        }
        if(sexEnum != null){
            userData.setSex(sexEnum.getSex());
            userData.setSex_value(sexEnum.getSex_value());
        }
        return userData;
    }
    /**
     * Demoフォームオブジェクトを生成する
     * @param id ID
     * @param name 名前
     * @param birthDay 生年月日
     * @param sexEnum 性別Enum
     * @return Demoフォームオブジェクト
     */
    private DemoForm makeDemoForm(Long id, String name, LocalDate birthDay
                                , SexEnum sexEnum){
        DemoForm demoForm = new DemoForm();
        if(id != null){
            demoForm.setId(String.valueOf(id));
        }
        demoForm.setName(name);
        if(birthDay != null){
            demoForm.setBirthYear(String.valueOf(birthDay.getYear()));
            demoForm.setBirthMonth(String.valueOf(birthDay.getMonthValue()));
            demoForm.setBirthDay(String.valueOf(birthDay.getDayOfMonth()));
        }
        if(sexEnum != null){
            demoForm.setSex(sexEnum.getSex());
            demoForm.setSex_value(sexEnum.getSex_value());
        }
        return demoForm;
    }
}
Mock化したメソッドの呼出回数は、「verify((Mock化したオブジェクト名), times((呼出回数))).(呼出メソッド名(呼出メソッドの引数))」という処理によって確認できる。
また、Mock化したメソッドの引数は、「ArgumentCaptor(引数のクラス名)> (オブジェクト名) = ArgumentCaptor.forClass((引数のクラス名).class);」と宣言し、verifyメソッドの呼出メソッドの引数に「(オブジェクト名).capture()」を指定した後で、「(オブジェクト名).getAllValues()」を実行することで、設定された引数のリストが取得できる。
その他のソースコード内容は、以下のサイトを参照のこと。
 https://github.com/purin-it/java/tree/master/junit-mockito-verify/demo
 
 
さらに、今回作成したJUnitプログラムを実行した結果は以下の通りで、コンソールに、Mock化したメソッドの呼出回数と引数が表示される。
 
要点まとめ
- Mock化したメソッドの呼出回数は、verifyメソッドにより取得できる。
- Mock化したメソッドの引数は、ArgumentCaptorクラスのオブジェクトにより取得できる。verifyメソッド呼出時にそのcaptureメソッドを指定した後で、そのオブジェクトのgetAllValuesメソッドを実行することで、設定された引数のリストが取得できる。





