JUnit

Spring Boot 2.7を利用したJavaアプリケーションでPowerMockを利用したテストを実行してみた

Spring Boot 2.7を利用したJavaアプリケーションでPowerMockを利用する際、mockito-coreやpowermockで特定のバージョンを指定することで、JUnit4とJUnit5に加え、PowerMockも利用可能となる。

今回は、Spring Boot 2.7を利用したJavaアプリケーションのJUnitによるテストコードで、PowerMockを利用してみたので、そのサンプルプログラムを共有する。

前提条件

下記記事の実装が完了していること。

Spring Boot 2.7を利用したJavaアプリケーションでJUnit4とJUnit5のテストを実行してみたSpring Boot 2.7を利用したJavaアプリケーションでJUnitを用いると、通常はJUnit5で動作するが、JUnit4とJ...

また、PowerMockを利用したテストコードの参照元は、下記記事とする。

JUnitのPowerMockを利用してstaticメソッドのMock化と呼出確認をしてみたこれまでは、Mockitoを利用してインスタンスメソッドをMock化する方法について記載していたが、今回はstaticメソッドのMock...

サンプルプログラムの作成

作成したサンプルプログラムの構成は、以下の通り。なお、下記の赤枠については、後述する。
サンプルプログラムの構成

pom.xmlの内容は以下の通りで、JUnit4, JUnit5に加え、PowerMockも利用できるよう、変更している。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>
  <groupId>com.example.demo</groupId>
  <artifactId>demoSpringTest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>demoSpringTest</name>
  <description>Demo Web Project for Spring Boot on Azure</description>
  <properties>
    <java.version>1.8</java.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-tomcat</artifactId>
      <scope>provided</scope>
    </dependency>
    <!-- バリデーションチェックを行うための設定 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <!-- lombokを利用するための設定 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <scope>provided</scope>
    </dependency>
    <!-- SQL Serverを利用するための設定 -->
    <!-- ドライバーが SSL (Secure Sockets Layer) 暗号化による
       SQL Server への安全な接続を確立できませんでした。というエラー
       (SQLServerException)を回避するため、SQL Serverに
                接続するためのJDBCドライバのバージョンを変更 -->
    <dependency>
      <groupId>com.microsoft.sqlserver</groupId>
      <artifactId>mssql-jdbc</artifactId>
      <version>9.4.1.jre8</version>
    </dependency>
    <!-- MyBatisを利用するための設定 -->
    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.3.2</version>
    </dependency>
    <!-- テスト用の設定 start -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <!-- Spring Boot 2.7の場合、デフォルトでJUnit5を利用するための設定を除外 -->
      <exclusions>
        <exclusion>
          <groupId>org.junit.jupiter</groupId>
          <artifactId>junit-jupiter</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
        <exclusion>
          <groupId>org.mockito</groupId>
          <artifactId>mockito-junit-jupiter</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    <!-- JUnit5を利用するための設定 -->
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter-engine</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.platform</groupId>
      <artifactId>junit-platform-launcher</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.junit.vintage</groupId>
      <artifactId>junit-vintage-engine</artifactId>
      <scope>test</scope>
    </dependency>
    <!-- JUnit5でMockitoを利用するための設定 -->
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-core</artifactId>
      <version>3.6.28</version> <!-- PowerMockを利用するため、バージョンを変更 -->
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-junit-jupiter</artifactId>
      <version>3.6.28</version> <!-- PowerMockを利用するため、バージョンを変更 -->
      <scope>test</scope>
    </dependency>
    <!-- JUnit4を利用するための設定(Mockitoも使える)  -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
    <!-- JUnit4でPowerMockを利用するための設定 -->
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-module-junit4</artifactId>
      <version>2.0.2</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.powermock</groupId>
      <artifactId>powermock-api-mockito2</artifactId>
      <version>2.0.2</version>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <artifactId>objenesis</artifactId>
          <groupId>org.objenesis</groupId>
        </exclusion>
        <exclusion>
          <artifactId>mockito-core</artifactId>
          <groupId>org.mockito</groupId>
        </exclusion>
      </exclusions>
    </dependency>    
    <!-- テスト用の設定 end -->
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

</project>

また、PowerMockを利用した際のソースコードは、以下の通り。

package com.example.demo;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;

import java.time.LocalDate;
import java.util.Map;

import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.springframework.validation.BindingResult;

import static org.junit.Assert.assertEquals;

//staticメソッドをMock化するにはPowerMockを利用
//@PrepareForTestアノテーションで、staticメソッドを含むクラスを指定
@RunWith(PowerMockRunner.class)
@PrepareForTest({DateCheckUtil.class})
public class DemoServiceImplTestPowermock {

  /**
   * テスト対象のクラス
   * (今回はSpring Bootを利用しないため、Serviceではなく
   * ServiceImplを対象クラスに指定している)
   */
  @InjectMocks
  private DemoServiceImpl demoServiceImpl;

  private DemoForm demoForm;

  private BindingResult bindingResult;
  
  /**
   * 初期化したMockオブジェクトを保持するクラス
   */
  private AutoCloseable closeable;

  /**
   * 前処理(各テストケースを実行する前に行われる処理)
   */
  @Before
  public void init() {
    /* @Mockアノテーションのモックオブジェクトを初期化
     * これを実行しないと@Mockアノテーション、@InjectMocksを付与した
     * Mockオブジェクトが利用できない
     * MockitoAnnotations.initMocksメソッドは非推奨となったため
     * 代わりにopenMocksメソッドを利用 */
    closeable = MockitoAnnotations.openMocks(this);

    //DateCheckUtilクラスをMock化
    PowerMockito.mockStatic(DateCheckUtil.class);

    //テスト対象メソッドの引数を設定
    demoForm = makeDemoForm(Long.valueOf(1), "テスト プリン"
        , LocalDate.of(2012, 1, 15), SexEnum.MAN);
    bindingResult = BindingResultModel.getBindingResult();
  }

  /**
   * DemoServiceImplクラスのcheckFormメソッド(DateCheckUtil.checkDateが正常時)の確認
   */
  @Test
  public void testCheckFormNormal() {
    //DateCheckUtilメソッドをMock化し、0が返却されるように設定
    PowerMockito.when(DateCheckUtil.checkDate(
        Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(0);

    //テスト対象メソッドの実行
    String returnVal = demoServiceImpl.checkForm(demoForm, bindingResult);

    //テスト対象メソッドを実行した結果、戻り値がconfirmであることを確認
    assertEquals("confirm", returnVal);

    //テスト対象メソッドを実行した結果、bindingResultに
    //エラーメッセージが設定されないことを確認
    Map<String, Object> mapObj = bindingResult.getModel();
    assertEquals(0, mapObj.size());
  }

  /**
   * DemoServiceImplクラスのcheckFormメソッド(DateCheckUtil.checkDateが異常時)の確認
   */
  @Test
  public void testCheckFormalDateError() {
    //DateCheckUtilメソッドをMock化し、4が返却されるように設定
    PowerMockito.when(DateCheckUtil.checkDate(
        Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(4);

    //テスト対象メソッドの実行
    String returnVal = demoServiceImpl.checkForm(demoForm, bindingResult);

    //テスト対象メソッドを実行した結果、戻り値がinputであることを確認
    assertEquals("input", returnVal);

    //テスト対象メソッドを実行した結果、resultに生年月日の日付が
    //不正な場合のエラーメッセージが設定されることを確認
    Map<String, Object> mapObj = bindingResult.getModel();
    BindingResultRejectValueModel resultModelYear
        = (BindingResultRejectValueModel) mapObj.get("birthYear");
    assertEquals("validation.date-invalidate", resultModelYear.getErrorCode());
    BindingResultRejectValueModel resultModelMonth
        = (BindingResultRejectValueModel) mapObj.get("birthMonth");
    assertEquals("validation.empty-msg", resultModelMonth.getErrorCode());
    BindingResultRejectValueModel resultModelDay
        = (BindingResultRejectValueModel) mapObj.get("birthDay");
    assertEquals("validation.empty-msg", resultModelDay.getErrorCode());
  }

  @Test
  public void testCheckFormDateCheckUtilArgs() {
    //DateCheckUtilメソッドをMock化し、0が返却されるように設定
    PowerMockito.when(DateCheckUtil.checkDate(
        Mockito.any(), Mockito.any(), Mockito.any())).thenReturn(0);

    //テスト対象メソッドの実行
    String returnVal = demoServiceImpl.checkForm(demoForm, bindingResult);

    //DateCheckUtilが呼ばれたときの引数を取得するための設定
    ArgumentCaptor<String> strYearArg = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<String> strMonthArg = ArgumentCaptor.forClass(String.class);
    ArgumentCaptor<String> strDayArg = ArgumentCaptor.forClass(String.class);

    //DateCheckUtilが1回呼ばれたことを確認
    PowerMockito.verifyStatic(DateCheckUtil.class, Mockito.times(1));
    DateCheckUtil.checkDate(
        strYearArg.capture(), strMonthArg.capture(), strDayArg.capture());

    //DateCheckUtilの引数が2012年1月15日の年月日であることを確認
    assertEquals("2012", strYearArg.getValue());
    assertEquals("1", strMonthArg.getValue());
    assertEquals("15", strDayArg.getValue());

    //テスト対象メソッドを実行した結果、戻り値がconfirmであることを確認
    assertEquals("confirm", returnVal);

    //テスト対象メソッドを実行した結果、bindingResultに
    //エラーメッセージが設定されないことを確認
    Map<String, Object> mapObj = bindingResult.getModel();
    assertEquals(0, mapObj.size());
  }
  
  /**
   * 後処理(各テストケースを実行した前に行われる処理)
   * @throws Exception 何らかの例外
   */
  @After  // JUnit4のアノテーション
  public void terminate() throws Exception {
    // Mockオブジェクトのリソースを解放
    closeable.close();
  }

  /**
   * 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;
  }

}

その他のソースコードについては、以下のサイトを参照のこと。
https://github.com/purin-it/java/tree/master/spring-boot-27-powermock/demoSpringTest/



サラリーマン型フリーランスSEという働き方でお金の不安を解消しよう先日、「サラリーマン型フリーランスSE」という働き方を紹介するYouTube動画を視聴しましたので、その内容をご紹介します。 「サ...

サンプルプログラムの実行結果

サンプルプログラム「DemoServiceImplTestPowermock.java」を実行した結果は、以下の通りで、正常に実行できている。
サンプルプログラムの実行結果

サンプルプログラムのpom.xml(テスト用の設定)の完成経緯

サンプルプログラムのpom.xml(テスト用の設定)が完成するまでの経緯は、以下の通り。

1) pom.xmlの「テスト用の設定」に、以下のように、PowerMockの設定を追加する。

<!-- テスト用の設定 start -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <!-- Spring Boot 2.7の場合、デフォルトでJUnit5を利用するための設定を除外 -->
    <exclusions>
        <exclusion>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- JUnit5を利用するための設定 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
</dependency>
<!-- JUnit5でMockitoを利用するための設定 -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <scope>test</scope>
</dependency>
<!-- JUnit4を利用するための設定(Mockitoも使える)  -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<!-- JUnit4でPowerMockを利用するための設定 -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.9</version>
    <scope>test</scope>
</dependency>
<!-- テスト用の設定 end -->

2) この状態で「DemoServiceImplTestJunit4.java」を実行した場合、以下のようなエラーが発生する。
経緯_2

org.opentest4j.MultipleFailuresError: Multiple Failures (2 failures)
  java.lang.NoClassDefFoundError: Could not initialize class org.mockito.Mockito
  java.lang.NullPointerException: <no message>
  at org.junit.vintage.engine.execution.TestRun.getStoredResultOrSuccessful(TestRun.java:196)
  at org.junit.vintage.engine.execution.RunListenerAdapter.fireExecutionFinished(RunListenerAdapter.java:226)
  at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:192)
  at org.junit.vintage.engine.execution.RunListenerAdapter.testFinished(RunListenerAdapter.java:79)
  at org.junit.runner.notification.SynchronizedRunListener.testFinished(SynchronizedRunListener.java:87)
  at org.junit.runner.notification.RunNotifier$9.notifyListener(RunNotifier.java:225)
  at org.junit.runner.notification.RunNotifier$SafeNotifier.run(RunNotifier.java:72)
  at org.junit.runner.notification.RunNotifier.fireTestFinished(RunNotifier.java:222)
  at org.junit.internal.runners.model.EachTestNotifier.fireTestFinished(EachTestNotifier.java:38)
  at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:372)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
  at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
  at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
  at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
  at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
  at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
  at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
  at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
  at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
  at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
  at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
  at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42)
  at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80)
  at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72)
  at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
  at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
  at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
  at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
  at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
  at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
  at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
  at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
  at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
  at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
  at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
  at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
  Suppressed: java.lang.NoClassDefFoundError: Could not initialize class org.mockito.Mockito
    at org.mockito.internal.configuration.MockAnnotationProcessor.processAnnotationForMock(MockAnnotationProcessor.java:33)
    at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:27)
    at org.mockito.internal.configuration.MockAnnotationProcessor.process(MockAnnotationProcessor.java:24)
    at org.mockito.internal.configuration.IndependentAnnotationEngine.createMockFor(IndependentAnnotationEngine.java:44)
    at org.mockito.internal.configuration.IndependentAnnotationEngine.process(IndependentAnnotationEngine.java:72)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.processIndependentAnnotations(InjectingAnnotationEngine.java:73)
    at org.mockito.internal.configuration.InjectingAnnotationEngine.process(InjectingAnnotationEngine.java:47)
    at org.mockito.MockitoAnnotations.openMocks(MockitoAnnotations.java:81)
    at com.example.demo.DemoServiceImplTestJunit4.init(DemoServiceImplTestJunit4.java:56)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    ... 29 more
  Suppressed: java.lang.NullPointerException
    at com.example.demo.DemoServiceImplTestJunit4.terminate(DemoServiceImplTestJunit4.java:151)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.RunAfters.invokeMethod(RunAfters.java:46)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    ... 29 more

3) この状態で「DemoServiceImplTestJunit5.java」を実行した場合、以下のように正常終了する。
経緯_3

4) pom.xmlの「テスト用の設定」の設定を、以下のように変更する。

<!-- テスト用の設定 start -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <!-- Spring Boot 2.7の場合、デフォルトでJUnit5を利用するための設定を除外 -->
    <exclusions>
        <exclusion>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-junit-jupiter</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- JUnit5を利用するための設定 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.platform</groupId>
    <artifactId>junit-platform-launcher</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.junit.vintage</groupId>
    <artifactId>junit-vintage-engine</artifactId>
    <scope>test</scope>
</dependency>
<!-- JUnit5でMockitoを利用するための設定 -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.6.28</version> <!-- PowerMockを利用するため、バージョンを変更 -->
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-junit-jupiter</artifactId>
    <version>3.6.28</version> <!-- PowerMockを利用するため、バージョンを変更 -->
    <scope>test</scope>
</dependency>
<!-- JUnit4を利用するための設定(Mockitoも使える)  -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <scope>test</scope>
</dependency>
<!-- JUnit4でPowerMockを利用するための設定 -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <artifactId>objenesis</artifactId>
            <groupId>org.objenesis</groupId>
        </exclusion>
        <exclusion>
            <artifactId>mockito-core</artifactId>
            <groupId>org.mockito</groupId>
        </exclusion>
    </exclusions>
</dependency>
<!-- テスト用の設定 end -->

上記は、下記サイトの最後の方にある、XiaoZhiSnowさんのコメントを参考に設定している。
https://github.com/mockito/mockito/issues/2568

5) この状態で「DemoServiceImplTestJunit4.java」を実行した場合、以下のように正常終了する。
経緯_5

6) この状態で「DemoServiceImplTestJunit5.java」を実行した場合も、以下のように正常終了する。
経緯_6

また、「DemoServiceImplTestPowermock.java」を実行した結果は、「サンプルプログラムの実行結果」に記載の通りとなる。

要点まとめ

  • Spring Boot 2.7を利用したJavaアプリケーションでJUnitを用いると、設定次第で、JUnit4とJUnit5の両方で動作した上で、PowerMockも利用できる。