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メソッドを実行することで、設定された引数のリストが取得できる。





