Skip to content

Mockitoの動的エージェントロード警告の解決策

問題

Spring Bootプロジェクトでテスト実行時に以下の警告が発生します:

log
Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK...
WARNING: Dynamic loading of agents will be disallowed by default in a future release

この警告はMockitoが動的にJavaエージェントをロードしていることが原因です。具体的には:

  • JDKの将来のバージョン(特にOpenJDK 21以降)でデフォルトでは動的エージェントロードが許可されなくなる仕様変更
  • byte-buddy-agentの動的ロードに関連する問題
  • Mockitoのinline-mock-maker機能との互換性問題

警告を無視すると、将来のJDKアップデートでテストが失敗する可能性があります。

解決アプローチ

根本的な解決策は以下の2点を組み合わせることです:

  1. -javaagentオプションで明示的にMockitoをエージェントとして読み込む
  2. -Xshare:offオプションでクラス共有を無効化する(共有エラーを回避)

実装方法

Mavenプロジェクトでの設定

pom.xmlに以下の設定を追加:

xml
<profiles>
    <profile>
        <id>mockito-config</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <argLine>
                            -javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar
                            -Xshare:off
                        </argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

${mockito.version}はSpring BootのBOMで管理されていますが、明示的にバージョン指定が必要な場合はプロパティを追加:

xml
<properties>
    <mockito.version>5.4.0</mockito.version> <!-- Spring Boot 3.4.0のデフォルト -->
</properties>

ポイント

${settings.localRepository}を使用することで、ユーザーごとのローカルリポジトリパスを動的に解決し環境依存を回避します

Gradleプロジェクトでの設定(Groovy)

build.gradleに以下の設定を追加:

groovy
def mockitoAgent = configurations.create("mockitoAgent")

dependencies {
    mockitoAgent("org.mockito:mockito-core") { transitive = false }
}

tasks.named('test') {
    jvmArgs(
        "-javaagent:${mockitoAgent.asPath}",
        "-Xshare:off"
    )
}

Gradleプロジェクトでの設定(Kotlin DSL)

build.gradle.ktsに追加:

kotlin
val mockitoAgent = configurations.create("mockitoAgent")

dependencies {
    mockitoAgent("org.mockito:mockito-core") {
        isTransitive = false
    }
}

tasks.withType<Test> {
    jvmArgs(
        "-javaagent:${mockitoAgent.asPath}",
        "-Xshare:off"
    )
}

重要

transitive = falseオプションを付与することで不要な依存関係を避け、クラスパスエラーを防止します

IDEでの追加設定

IntelliJ IDEA の場合

  1. [Preferences > Build Tools > Gradle] を開く
  2. 「Run tests using:」を「Gradle」に設定

またはVMオプションを直接指定:

  1. テストクラス右クリック >
  2. 「Modify Run Configuration...」 >
  3. 「VM options」に追加:
    -javaagent:/path/to/mockito-core.jar -Xshare:off

Eclipse の場合

  1. Run Configurationの設定を開く
  2. 「Arguments」タブの「VM arguments」に追加:
    -javaagent:C:\\Users\\<user>\\.m2\\repository\\org\\mockito\\mockito-core\\5.4.0\\mockito-core-5.4.0.jar
    -Xshare:off
    パスは実際の環境に合わせ修正

技術的背景解説

なぜこの設定が必要か?

  • 動的エージェントロードの制限
    Java 9以降のモジュールシステム導入で、セキュリティ上の理由から動的エージェントロードが段階的に制限されています

  • Mockitoの動作メカニズム
    モック生成のためにByteBuddyを利用し、実行時コード生成を行うためエージェントが必要です

  • -Xshare:offの重要性
    JVMのクラスデータ共有(CDS)とMockitoの相性問題を解消し、bootstrap classpath has been appended警告を除去

非推奨アプローチ

以下の方法は非推奨です:

  • maven-dependency-plugin@{argLine}の組み合わせ
  • 動的パス解決なしの絶対パス指定
  • -XX:+EnableDynamicAgentLoadingオプション

検証済み環境

本解決策が確認された環境:

  • Java: OpenJDK 21.0.4
  • ビルドツール:
    • Maven 3.9.9
    • Gradle 8.6
  • Spring Boot: 3.4.0
  • Mockito: 5.4.0(Spring Boot依存)
  • IDE: IntelliJ IDEA 2024.1, Eclipse 2024-03

設定適用後、警告メッセージが完全に消え、テストが正常実行されることを確認してください。これにより将来のJDKアップデートでも互換性が保証されます。