privateメソッドの場合も、staticメソッドの場合と同様に、PowerMockを利用してMock化することができる。今回は、privateメソッドのMock化と呼出確認を行ってみたので、そのサンプルプログラムを共有する。
前提条件
下記記事の実装が完了していること。
サンプルプログラムの内容
作成したサンプルプログラムの構成は以下の通り。

なお、上記の赤枠のうち、「DateCheckUtil.java」がテスト対象のプログラムで、「DateCheckUtilTest.java」が今回新規で作成したプログラムとなる。
DateCheckUtil.javaの内容は以下の通り。そのうち、今回のテストプログラムに関連するのは「checkDate」「isCorrectDate」メソッドとなる。
package com.example.demo;
import java.time.LocalDate;
import java.time.chrono.JapaneseChronology;
import java.time.format.DateTimeFormatter;
import java.time.format.ResolverStyle;
import java.util.Locale;
public class DateCheckUtil {
/**
* 日付チェック処理を行う
* @param year 年
* @param month 月
* @param day 日
* @return 判定結果(1:年が空、2:月が空、3:日が空、4:年月日が不正、5:年月日が未来日、0:正常
*/
public static int checkDate(String year, String month, String day){
final String dateFormat = "uuuuMMdd";
if(isEmpty(year)){
return 1;
}
if(isEmpty(month)){
return 2;
}
if(isEmpty(day)){
return 3;
}
String dateStr = year + addZero(month) + addZero(day);
if(!isCorrectDate(dateStr, dateFormat)){
return 4;
}
if(isFutureDate(dateStr, dateFormat)){
return 5;
}
return 0;
}
/**
* DateTimeFormatterを利用して日付チェックを行う
* @param dateStr チェック対象文字列
* @param dateFormat 日付フォーマット
* @return 日付チェック結果
*/
private static boolean isCorrectDate(String dateStr, String dateFormat){
if(isEmpty(dateStr) || isEmpty(dateFormat)){
return false;
}
//日付と時刻を厳密に解決するスタイルで、DateTimeFormatterオブジェクトを作成
DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat)
.withResolverStyle(ResolverStyle.STRICT);
try{
//チェック対象文字列をLocalDate型の日付に変換できれば、チェックOKとする
LocalDate.parse(dateStr, df);
return true;
}catch(Exception e){
return false;
}
}
/**
* 日付の文字列が未来日かどうかを判定する
* @param dateStr チェック対象文字列
* @param dateFormat 日付フォーマット
* @return 判定結果
*/
private static boolean isFutureDate(String dateStr, String dateFormat){
if(!isCorrectDate(dateStr, dateFormat)){
return false;
}
LocalDate dateStrDate = convertStrToLocalDate(dateStr, dateFormat);
LocalDate now = LocalDate.now();
if(dateStrDate.isAfter(now)){
return true;
}
return false;
}
/**
* 日付の文字列を日付型に変換した結果を返す
* @param dateStr 日付の文字列
* @param dateFormat 日付のフォーマット
* @return 変換後の文字列
*/
private static LocalDate convertStrToLocalDate(String dateStr, String dateFormat){
if(isEmpty(dateStr) || isEmpty(dateFormat)){
return null;
}
//日付と時刻を厳密に解決するスタイルで、暦体系は和暦体系で、
//DateTimeFormatterオブジェクトを作成
DateTimeFormatter df = DateTimeFormatter.ofPattern(dateFormat, Locale.JAPAN)
.withChronology(JapaneseChronology.INSTANCE)
.withResolverStyle(ResolverStyle.STRICT);
//日付の文字列をLocalDate型に変換して返却
return LocalDate.parse(dateStr, df);
}
/**
* 数値文字列が1桁の場合、頭に0を付けて返す
* @param intNum 数値文字列
* @return 変換後数値文字列
*/
private static String addZero(String intNum){
if(isEmpty(intNum)){
return intNum;
}
if(intNum.length() == 1){
return "0" + intNum;
}
return intNum;
}
/**
* 引数の文字列がnull、空文字かどうかを判定する
* @param str チェック対象文字列
* @return 文字列チェック結果
*/
public static boolean isEmpty(String str){
if(str == null || "".equals(str)){
return true;
}
return false;
}
}
また、DateCheckUtilTest.javaの内容は以下の通り。
package com.example.demo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.junit.Assert.assertEquals;
@RunWith(PowerMockRunner.class)
@PrepareForTest({DateCheckUtil.class})
public class DateCheckUtilTest {
/**
* 前処理(各テストケースを実行する前に行われる処理)
*/
@Before
public void init(){
//DateCheckUtilクラスをSpyで一部をMock設定
PowerMockito.spy(DateCheckUtil.class);
}
/**
* DateCheckUtilクラスのcheckDateメソッドの確認
* (DateCheckUtil.isCorrectDateをMock設定した場合の確認)
*/
@Test
public void testDateCheckUtilCheckDateMock() throws Exception{
//privateメソッドであるDateCheckUtil.isCorrectDateを呼び出したときに、
//falseを返却するようMock設定
PowerMockito.doReturn(false)
.when(DateCheckUtil.class, "isCorrectDate"
, Mockito.any(), Mockito.any());
//DateCheckUtil.checkDateを呼び出し、戻り値を確認
//checkDateメソッドの引数に正しい年月日を指定しているが、
//isCorrectDateメソッドでfalseを返すようにMock設定したため、
//DateCheckUtil.checkDateメソッドの戻り値が4になる
int retVal = DateCheckUtil.checkDate("2012", "12", "27");
assertEquals(4, retVal);
}
/**
* DateCheckUtilクラスのcheckDateメソッドの確認
* (DateCheckUtil.isCorrectDateの呼出回数と引数の確認)
*/
@Test
public void testDateCheckUtilCheckDateVerify() throws Exception{
//DateCheckUtil.checkDateを呼び出し、戻り値を確認
int retVal = DateCheckUtil.checkDate("2012", "12", "32");
assertEquals(4, retVal);
//DateCheckUtil.isCorrectDateメソッドの呼出回数が1回であることを確認し、
//その際の引数も取得
ArgumentCaptor<String> dateStrArg = ArgumentCaptor.forClass(String.class);
ArgumentCaptor<String> dateFormatArg = ArgumentCaptor.forClass(String.class);
PowerMockito.verifyPrivate(DateCheckUtil.class, Mockito.times(1))
.invoke("isCorrectDate", dateStrArg.capture(), dateFormatArg.capture());
//DateCheckUtil.isCorrectDateメソッドの引数を確認
assertEquals("20121232", dateStrArg.getValue());
assertEquals("uuuuMMdd", dateFormatArg.getValue());
}
}
上記プログラムのtestDateCheckUtilCheckDateMockメソッドでは、DateCheckUtil.javaのprivateメソッド「isCorrectDate」をMock化している。PowerMockitoのwhen句で、staticメソッドの場合と同じように、第一引数にstaticメソッドを含むクラス名.classを、第二引数にメソッド名を、第三引数以降にメソッドの引数(任意値はMockito.any()で指定)を指定している。
また、testDateCheckUtilCheckDateVerifyメソッドでは、DateCheckUtil.javaのprivateメソッド「isCorrectDate」の呼出回数と引数を取得している。PowerMockito.verifyPrivateメソッドを利用し、呼出回数はMockito.times句で確認し、invokeメソッド内でメソッド名と引数の指定を行っている。さらに、staticメソッドの場合と同様に、そのメソッド呼出時の引数は、ArgumentCaptorクラスを利用することで取得できる。
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/junit-powermock-private/demo
今回作成した「DateCheckUtilTest.java」の実行結果は以下の通り。

要点まとめ
- privateメソッドの場合も、PowerMockを利用することで、Mock化や呼出回数・引数の確認が行える。






