Mockitoのバージョンが2の場合、MockMakerファイルを配置すれば、finalメソッドをMock化することができる。今回は、MockMakerファイルを配置した上で、finalメソッドをMock化するサンプルプログラムを作成してみたので、共有する。
前提条件
下記記事の実装が完了していること。
また、以下のように、Mockitoのバージョンが2であること。

作成したサンプルプログラムの内容と実行結果
作成したサンプルプログラムの構成は以下の通り。

なお、上記の赤枠は、前提条件のプログラムから変更したプログラムである。
src/mainフォルダ下の変更したプログラムの内容は以下の通りで、コントローラクラスで、finalメソッドとfinalでないメソッドの両方を呼び出している。
package com.example.demo;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class DemoComponent {
/**
* 現在日時を取得し返却する
* @return 現在日時
*/
public String getNowDateTime(){
LocalDateTime nowDateTime = LocalDateTime.now();
return nowDateTime.toString();
}
/**
* finalメソッドで現在日時を取得し返却する
* @return 現在日時
*/
public final String getNowDateTimeFinal(){
LocalDateTime nowDateTime = LocalDateTime.now();
return nowDateTime.toString();
}
}
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class DemoController {
/**
* DemoComponentクラス
*/
@Autowired
DemoComponent demoComponent;
/**
* 初期表示画面に遷移する
* @param model Modelオブジェクト
* @return 初期表示画面へのパス
*/
@RequestMapping("/")
public String index(Model model){
String nowDateTime = demoComponent.getNowDateTime();
String nowDateTimeFinal = demoComponent.getNowDateTimeFinal();
model.addAttribute("nowDateTime", nowDateTime);
model.addAttribute("nowDateTimeFinal", nowDateTimeFinal);
return "index";
}
}
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>index page</title>
</head>
<body>
nowDateTimeの値: <span th:text="${nowDateTime}">nowDateTimeの値</span><br/><br/>
nowDateTimeFinalの値: <span th:text="${nowDateTimeFinal}">nowDateTimeFinalの値</span>
</body>
</html>上記ソース内容で、 Spring Bootアプリケーションを起動し、「http:// (ホスト名):(ポート番号)」とアクセスすると、以下の画面が表示される。

また、MockMakerのファイルは以下のように、「src/test/resources/mockito-extensions」フォルダ下に、「org.mockito.plugins.MockMaker」というファイル名で作成し、そのファイルに「mock-maker-inline」と記載する必要がある。

さらに、コントローラクラスのテストを行うプログラムの内容は以下の通りで、finalメソッドであるgetNowDateTimeFinalメソッドも、finalメソッドでないgetNowDateTimeメソッドも、Mock化できている。
package com.example.demo;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.ui.Model;
import java.time.LocalDateTime;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;
public class DemoControllerTest {
/**
* テスト対象のクラス
*/
@InjectMocks
private DemoController demoController;
/**
* テスト対象のクラス内で呼ばれるクラスのMockオブジェクト
*/
@Mock
private DemoComponent demoComponent;
/**
* 前処理(各テストケースを実行する前に行われる処理)
*/
@Before
public void init(){
//@Mockアノテーションのモックオブジェクトを初期化
//これを実行しないと@Mockアノテーション、@InjectMocksを付与した
//Mockオブジェクトが利用できない
MockitoAnnotations.initMocks(this);
//Mockの設定
when(demoComponent.getNowDateTime()).thenReturn(getNowDateTimeStr());
when(demoComponent.getNowDateTimeFinal()).thenReturn(getNowDateTimeStr());
}
/**
* DemoControllerクラスのindexメソッドを確認
*/
@Test
public void testDemoController(){
//Modelオブジェクトを生成
Model model = DemoControllerTestUtil.getModel();
//テスト対象クラスのメソッドを実行
String strPath = demoController.index(model);
//テスト対象クラスのメソッドで設定されたMapオブジェクトを表示
System.out.println();
System.out.println("*** コントローラクラスのindexメソッドで設定されたMapオブジェクト ***");
System.out.println(model.asMap());
System.out.println();
//テスト対象クラスのメソッドの実行結果を確認
assertEquals("index", strPath);
Map<String, Object> mapObj = model.asMap();
assertEquals("2020-07-14T20:54:12", mapObj.get("nowDateTime"));
assertEquals("2020-07-14T20:54:12", mapObj.get("nowDateTimeFinal"));
}
/**
* 現在時刻を生成し文字列化して返却
* @return 現在時刻の文字列
*/
private String getNowDateTimeStr(){
LocalDateTime nowDateTime = LocalDateTime.of(
2020, 7, 14, 20, 54, 12);
return nowDateTime.toString();
}
}
また、Modelオブジェクトを生成し返却するプログラムの内容は以下の通りで、先ほどのDemoControllerTestクラスで呼び出している。
package com.example.demo;
import org.springframework.ui.Model;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class DemoControllerTestUtil {
/**
* Modelオブジェクトを生成し返却する
* @return Modelオブジェクト
*/
public static Model getModel(){
return new Model() {
private Map<String, Object> modelMap = new HashMap<>();
@Override
public Model addAttribute(String attributeName, Object attributeValue) {
modelMap.put(attributeName, attributeValue);
return null;
}
@Override
public Model addAttribute(Object attributeValue) {
return null;
}
@Override
public Model addAllAttributes(Collection<?> attributeValues) {
return null;
}
@Override
public Model addAllAttributes(Map<String, ?> attributes) {
return null;
}
@Override
public Model mergeAttributes(Map<String, ?> attributes) {
return null;
}
@Override
public boolean containsAttribute(String attributeName) {
return false;
}
@Override
public Map<String, Object> asMap() {
return modelMap;
}
};
}
}
その他のソースコード内容は、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/junit-mockito-final/demo
DemoControllerTestクラスを実行した結果は以下の通りで、finalメソッドであるgetNowDateTimeFinalメソッドも、finalメソッドでないgetNowDateTimeメソッドも、Mock化により返却された値が設定されることが確認できる。

要点まとめ
- Mockitoのバージョンが2の場合、MockMakerファイルを配置すれば、finalメソッドをMock化することができる。
- MockMakerのファイルは「src/test/resources/mockito-extensions」フォルダ下に「org.mockito.plugins.MockMaker」というファイル名で作成し、そのファイルに「mock-maker-inline」と記載すればよい。





