Mockito
inline-mock-maker
Java Development Kit
JDK updates
software testing

Mockito is currently self-attaching to enable the inline-mock-maker. This will no longer work in future releases of the JDK

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you see the warning about Mockito self-attaching, your tests are using inline mocking features that depend on JVM instrumentation at runtime. Newer JDK security direction reduces support for dynamic agent attachment, so builds should move to explicit test-time agent configuration. This article explains why the warning appears and how to fix it in a forward-compatible way.

Why the Warning Appears

Mockito inline mock maker enables features such as mocking final classes and static methods. To do this, Mockito relies on bytecode instrumentation. Historically, Mockito could attach an agent dynamically when tests started. The warning means this fallback path is being deprecated by JDK changes.

In practical terms, tests may still pass today but can fail on future JDK releases if no explicit agent is configured.

Identify Whether You Need Inline Mocking

If your test suite only mocks interfaces and non-final instance methods, default mocking may be enough. If you use mockStatic, mock final classes, or advanced constructor interception, inline mode is required.

Example test that requires inline support:

java
1import static org.mockito.Mockito.*;
2import org.junit.jupiter.api.Test;
3
4class ClockUtil {
5    static String now() {
6        return "2026-01-01";
7    }
8}
9
10class ClockUtilTest {
11    @Test
12    void testStaticMock() {
13        try (var mocked = mockStatic(ClockUtil.class)) {
14            mocked.when(ClockUtil::now).thenReturn("fixed");
15            assert ClockUtil.now().equals("fixed");
16        }
17    }
18}

Without instrumentation, this style fails.

Configure Explicit Java Agent in Gradle

A robust Gradle setup resolves the Mockito test artifact and passes it as -javaagent to the test JVM.

gradle
1dependencies {
2    testImplementation "org.mockito:mockito-core:5.12.0"
3    testImplementation "org.junit.jupiter:junit-jupiter:5.11.0"
4
5    testRuntimeOnly "org.junit.platform:junit-platform-launcher"
6    testRuntimeOnly "org.mockito:mockito-core:5.12.0"
7}
8
9tasks.test {
10    useJUnitPlatform()
11    def mockitoJar = configurations.testRuntimeClasspath.find {
12        it.name.startsWith("mockito-core")
13    }
14    jvmArgs "-javaagent:${mockitoJar.absolutePath}"
15}

This avoids dynamic attach and keeps behavior explicit.

Configure Explicit Java Agent in Maven

For Maven Surefire, you can set argLine to include the Mockito core jar from local repository.

xml
1<properties>
2  <mockito.version>5.12.0</mockito.version>
3</properties>
4
5<dependencies>
6  <dependency>
7    <groupId>org.mockito</groupId>
8    <artifactId>mockito-core</artifactId>
9    <version>${mockito.version}</version>
10    <scope>test</scope>
11  </dependency>
12</dependencies>
13
14<build>
15  <plugins>
16    <plugin>
17      <groupId>org.apache.maven.plugins</groupId>
18      <artifactId>maven-surefire-plugin</artifactId>
19      <version>3.2.5</version>
20      <configuration>
21        <argLine>-javaagent:${settings.localRepository}/org/mockito/mockito-core/${mockito.version}/mockito-core-${mockito.version}.jar</argLine>
22      </configuration>
23    </plugin>
24  </plugins>
25</build>

If your organization uses a custom local repository layout, adapt the path accordingly.

Migration Strategy for Existing Test Suites

Teams often discover this warning after a JDK upgrade in CI. A safe migration is incremental instead of editing every module at once.

  1. Add explicit agent configuration in one module.
  2. Run tests on the current JDK and next planned JDK.
  3. Apply the same test task setup to remaining modules.
  4. Remove old inline configuration files that conflict with new setup.

Use a small smoke test to confirm instrumentation is active.

java
1import static org.mockito.Mockito.*;
2import org.junit.jupiter.api.Test;
3
4final class FinalService {
5    String value() { return "real"; }
6}
7
8class FinalServiceTest {
9    @Test
10    void canMockFinalClass() {
11        FinalService svc = mock(FinalService.class);
12        when(svc.value()).thenReturn("mock");
13        assert svc.value().equals("mock");
14    }
15}

If this smoke test fails, inspect test JVM arguments first. Most failures come from agent path resolution rather than Mockito API usage.

Keep Test Stack Up to Date

Agent setup alone is not enough if dependency versions drift.

  • Keep Mockito and JUnit versions current.
  • Run tests on your target JDK version in CI.
  • Remove legacy mockito-inline usage if your chosen Mockito release already handles inline features via configured agent.
  • Review release notes before major JDK upgrades.

A matrix CI job that runs tests on current and next JDK helps catch instrumentation regressions early.

Common Pitfalls

  • Ignoring the warning because tests still pass today.
  • Configuring -javaagent in application runtime instead of test runtime only.
  • Depending on transitive Mockito versions and losing control of behavior across modules.
  • Mixing old and new mock maker setup in the same multi-module build.
  • Upgrading JDK in CI without verifying test JVM args are still applied.

Summary

  • The warning signals future incompatibility with dynamic self-attachment.
  • Inline mocking needs explicit agent configuration for long-term stability.
  • Configure -javaagent in Gradle or Maven test execution.
  • Validate on current and upcoming JDK versions in CI.
  • Keep Mockito configuration centralized so upgrades are predictable.

Course illustration
Course illustration

All Rights Reserved.