skip to content

How do you select which mock maker Mockito uses, and what happened to the mockito-inline artifact people used to add to their test dependencies?

level: middleimportance: should knowfreq 42%

answer

  1. mockito-extensions/org.mockito.plugins.MockMaker resource
  2. content: mock-maker-inline / mock-maker-subclass
  3. Mockito 5 default = inline in mockito-core
  4. mockito-inline retired; mockito-subclass for the old behaviour
  5. @Mock(mockMaker = MockMakers.SUBCLASS) since 4.8

basics

~20 s

Since Mockito 5 the inline maker is the default in mockito-core, so nothing is needed. Otherwise put a file mockito-extensions/org.mockito.plugins.MockMaker on the test classpath containing mock-maker-inline. The mockito-inline artifact existed only to flip that default and is retired; mockito-subclass now provides the old behaviour.

solid answer

~40 s

Three levels of control: 1. **Default.** Mockito 5.0+ ships the inline maker as the default of `mockito-core`. On Mockito 2–4 the default was the subclass maker. 2. **Classpath-wide override.** Create `src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker` whose single line is `mock-maker-inline` or `mock-maker-subclass`. Mockito's plugin loader reads that resource at startup. (A fully-qualified `MockMaker` implementation class name works too, for custom makers.) 3. **Per mock.** Since Mockito 4.8: `@Mock(mockMaker = MockMakers.SUBCLASS)` or `mock(Foo.class, withSettings().mockMaker(MockMakers.INLINE))`. The old `mockito-inline` artifact was nothing but `mockito-core` plus that resource file preselecting the inline maker. Once Mockito 5 made inline the default it became redundant and was discontinued after 5.2. If you still need the subclass behaviour — Android, or a JVM where the agent cannot attach — depend on `mockito-subclass` instead.

code

java · 15 lines
java
@ExtendWith(MockitoExtension.class)
class MixedMakersTest {

    @Mock(mockMaker = MockMakers.SUBCLASS)
    LegacyService legacy;

    @Test
    void inlineForOneMock() {
        FinalConfig config = mock(FinalConfig.class,
                withSettings().mockMaker(MockMakers.INLINE));
        when(config.timeoutSeconds()).thenReturn(5);

        assertEquals(5, config.timeoutSeconds());
    }
}

go deeper

for a junior

Know that Mockito 5 needs no extra setup for final classes, and that mockito-inline was the old opt-in.

for a middle

Describe the extensions resource file, its two token values, and the artifact history including mockito-subclass.

for a senior

Handle multi-module and BOM-managed builds, competing extension resources, and per-mock MockMakers selection.

for a principal

Set a project-wide convention for mock-maker selection and treat a Mockito major bump as a behavioural change requiring a note in the migration plan.

## The plugin mechanism `MockMaker` is one of Mockito's service-provider extension points. At startup Mockito's plugin loader looks for a resource named `mockito-extensions/org.mockito.plugins.MockMaker` anywhere on the classpath. The file's content is a single token naming the implementation: - `mock-maker-inline` — the instrumentation-based maker; - `mock-maker-subclass` — the classic ByteBuddy subclassing maker; - or the fully qualified class name of your own `MockMaker`. The same directory hosts sibling extension points (`org.mockito.plugins.MockitoLogger`, `...InstantiatorProvider2`, `...StackTraceCleanerProvider`). In a Gradle or Maven project the file goes to `src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker` so it lands on the test runtime classpath. A sharp edge: only one such resource should be visible. If two dependencies each contribute one, which wins is classpath-order dependent and effectively arbitrary — a real source of "works on my machine" behaviour. ## The artifact history - **Mockito 2–4**: `mockito-core` defaults to the subclass maker. To get the inline maker you either wrote the resource file yourself or depended on **`mockito-inline`**, an artifact that was simply `mockito-core` with that resource baked in. That is the only thing it ever did. - **Mockito 5.0 (2023)**: the default in `mockito-core` flipped to the inline maker, and the minimum Java version rose to 11. `mockito-inline` became a no-op wrapper and was discontinued (its last release is in the 5.x line); build files that still reference it should just drop the dependency. - **`mockito-subclass`**: introduced alongside Mockito 5 as the mirror image — `mockito-core` plus a resource preselecting `mock-maker-subclass` — for environments where instrumentation is not available or not wanted. Interviewers ask about this because plenty of build files still carry `mockito-inline` on Mockito 5, which is dead weight, and because knowing *why* it existed demonstrates understanding of the plugin mechanism rather than dependency cargo-culting. ## Per-mock selection Mockito 4.8 added a way to choose the maker for a single mock, which is useful when the classpath-wide choice does not suit one particular type: ```java @Mock(mockMaker = MockMakers.SUBCLASS) LegacyService legacy; HeavyType heavy = mock(HeavyType.class, withSettings().mockMaker(MockMakers.INLINE)); ``` `MockMakers` holds the constants `INLINE` and `SUBCLASS` (the same tokens as the resource file). Typical reasons to reach for it: a type that the inline maker cannot instrument, or a hot path in a large suite where subclass mocks are cheaper for a repeatedly mocked simple interface. ## Verifying what is actually active When in doubt, the fastest empirical check is behavioural: try mocking a final class. If it fails with "Cannot mock/spy because: final class", the subclass maker is active. `Mockito.framework().getPlugins().getInlineMockMaker()` and the mock-maker information Mockito prints in some failure messages also help. In a multi-module build, check every module's test classpath — the resource file only affects modules that can see it, so one module can behave differently from another. ## Spring Boot and managed dependencies If the Mockito version comes from a BOM (Spring Boot's dependency management, for instance), the mock-maker default follows that managed version. Overriding `mockito.version` to move from 4.x to 5.x therefore changes mocking behaviour project-wide — usually for the better, but it is a real behavioural change to note in a version bump, especially for suites that relied on final methods running for real on spies.

  • A project on Mockito 5 still declares mockito-inline as a test dependency. What should you do?
    Remove it. On Mockito 5 mockito-core already defaults to the inline maker, so the artifact adds nothing and is no longer released alongside new versions; keeping it risks pinning an older Mockito on the classpath. If the project genuinely needs the subclass maker, swap to mockito-subclass rather than keeping the retired artifact.
  • Two libraries on your test classpath each ship a MockMaker extension resource. What happens?
    Mockito's plugin loader picks one, and which one depends on classpath ordering, so the effective mock maker becomes non-deterministic across environments. The remedy is to make the choice explicit in your own module — your own resource file or per-mock MockMakers settings — and to exclude the transitive artifact that carries the competing resource.
  • When would you deliberately choose MockMakers.SUBCLASS for a single mock?
    When the type cannot be instrumented safely or the inline path fails for it, or when profiling shows repeated instrumentation cost for a simple, heavily mocked interface. It is also a quick isolation step while diagnosing whether a strange test failure comes from instrumentation. Otherwise leave the classpath default in place.

saying these in an interview costs you the question

  • Thinking mockito-inline is still required on Mockito 5
  • Believing the mock maker is chosen by an API call at runtime only (missing the resource file)
  • Putting the extensions resource in main resources instead of test resources
  • Not knowing mockito-subclass exists for environments without instrumentation
  • Assuming the resource file affects modules that cannot see it on their classpath

context