skip to content

Annotation Initialization

Annotations do nothing until something processes them: MockitoExtension in JUnit 5, MockitoAnnotations.openMocks as the framework-agnostic fallback, or the legacy JUnit 4 runner/rule. Interviewers ask which to use where, and what openMocks' AutoCloseable contract means for teardown.

on this pageshow

questions

4

A test class declares fields annotated with Mockito's @Mock, and the test fails with NullPointerException the first time one of those fields is used. Why are they null, and what are the ways to make them non-null?

level: juniorimportance: must knowfreq 62%

answer

  1. annotation is inert metadata
  2. extension / openMocks / runner-or-rule — pick one
  3. @RunWith silently ignored by JUnit 5
  4. mixed JUnit 4 + 5 imports = setup never runs
  5. mockito-junit-jupiter artifact needed for the extension

basics

~20 s

@Mock is only metadata; something must scan the test instance and assign the mocks. Enable one initializer: @ExtendWith(MockitoExtension.class) on JUnit 5, MockitoAnnotations.openMocks(this) in a setup method, or the JUnit 4 MockitoJUnitRunner/MockitoRule. Without one, the fields stay null.

solid answer

~40 s

Annotations do nothing on their own. Some component has to reflect over the test instance's fields, create a mock for each `@Mock` (and `@Spy`, `@Captor`, then populate `@InjectMocks`) and assign them. Mockito ships three such initializers: - **JUnit 5:** `@ExtendWith(MockitoExtension.class)` on the class (from `mockito-junit-jupiter`). - **Framework-agnostic:** `MockitoAnnotations.openMocks(this)` called in `@BeforeEach`/`@Before`/`setUp`; it returns an `AutoCloseable` you should close afterwards. - **JUnit 4:** `@RunWith(MockitoJUnitRunner.class)` or a `@Rule public MockitoRule rule = MockitoJUnit.rule();`. The usual causes of the failure are: no initializer at all; a JUnit 4 `@RunWith` left on a class now executed by JUnit 5, which ignores it entirely; mixed `org.junit.Test` and `org.junit.jupiter.api.Test` imports so the setup method never runs; or the initializer being invoked after the fields are used.

code

java · 15 lines
java
@ExtendWith(MockitoExtension.class)
class WithExtensionTest {
    @Mock OrderRepository repository;      // non-null before each test
}

class WithOpenMocksTest {
    @Mock OrderRepository repository;
    private AutoCloseable mocks;

    @BeforeEach
    void init() { mocks = MockitoAnnotations.openMocks(this); }

    @AfterEach
    void release() throws Exception { mocks.close(); }
}

go deeper

for a junior

Recall that an initializer is required and name at least the JUnit 5 extension and openMocks(this).

for a middle

Name all three mechanisms, know which JUnit generation each belongs to, and explain the silently-ignored @RunWith trap.

for a senior

Add the diagnosis checklist — one initializer, engine match, consistent imports, artifact present — and why stacking initializers loses stubbing.

for a principal

Set the team convention: one initializer declared in a shared base class or template, consistent JUnit generation across the module, so this class of failure cannot recur.

## Why the field is null `@Mock` is a plain annotation retained at runtime. Declaring it changes nothing about the field: at construction time the JVM initializes it to `null` like any uninitialized reference. Something must *process* the annotation — walk the test instance's declared fields (including inherited ones), see the annotation, call `Mockito.mock(...)` with the field's type and name, and assign the result by reflection. Mockito ships three processors, and you pick exactly one. ## Option 1 — the JUnit 5 extension ```java @ExtendWith(MockitoExtension.class) class CheckoutServiceTest { @Mock OrderRepository repository; } ``` It lives in the separate `mockito-junit-jupiter` artifact (test scope), so a missing dependency shows up as an unresolvable `MockitoExtension`. The extension initializes annotated fields before each test method, tears down afterwards, applies strict stubs by default, and can also resolve `@Mock`-annotated **parameters** of test and lifecycle methods — handy for a mock only one test needs. ## Option 2 — openMocks, called explicitly ```java class CheckoutServiceTest { @Mock OrderRepository repository; private AutoCloseable mocks; @BeforeEach void init() { mocks = MockitoAnnotations.openMocks(this); } @AfterEach void tearDown() throws Exception { mocks.close(); } } ``` This is framework-agnostic — JUnit 4, JUnit 5, TestNG, or a plain `main`. It is the escape hatch when you cannot register the extension, for example inside a test infrastructure base class shared across frameworks. `openMocks` replaced the older `initMocks(this)`, which is deprecated because it did not give you the closeable handle. ## Option 3 — the JUnit 4 runner or rule `@RunWith(MockitoJUnitRunner.class)` initializes annotations and validates Mockito usage after each test. `@Rule public MockitoRule rule = MockitoJUnit.rule();` does the same while leaving the runner slot free for another runner (a parameterized runner, a Spring runner). Both are JUnit 4 only. ## The failure modes that produce null fields 1. **No initializer at all.** The most common by far, especially when a test class is created by copying one that had the extension and dropping the annotation. 2. **A JUnit 4 runner on a JUnit 5 test.** JUnit Jupiter does not understand `@RunWith`; it neither honours it nor complains, so the class runs with uninitialized mocks. The same happens with a JUnit 4 `@Rule` field under Jupiter. 3. **Mixed imports.** `@BeforeEach` from Jupiter combined with `org.junit.Test` (JUnit 4), or vice versa: the setup method belongs to a lifecycle the executing engine ignores, so `openMocks` never runs. Symptom: mocks are null even though the setup method visibly exists. 4. **The initializer runs too late or not for this instance.** Calling `openMocks(this)` from a helper that receives a different object, or initializing in `@BeforeAll` (static, wrong instance), leaves the per-test fields null. 5. **The annotation is not Mockito's.** Importing a different framework's `@Mock` — or Spring's bean-replacing mock annotation, which requires a Spring test context rather than the Mockito extension — is a quiet copy-paste trap. 6. **The field is static, or the class is executed by an engine that constructs test instances differently.** Mockito's processors assign instance fields on the test instance they are handed. ## Diagnosing quickly Ask in order: Is there exactly one initializer? Does the executing engine match it (Jupiter extension vs JUnit 4 runner/rule)? Are all lifecycle and test annotations from the same JUnit generation? Is `mockito-junit-jupiter` on the test classpath? Is the setup method non-static and non-private? That checklist covers essentially every occurrence. ## Do not stack initializers Registering the extension *and* calling `openMocks` in `@BeforeEach` is redundant: fields are created twice, the second set replacing the first, and any stubbing done between the two is lost. It also confuses session validation. Pick one mechanism per class and let base classes declare it rather than each subclass repeating it. ## A note on the alternative You can always avoid the question entirely by creating collaborators with `Mockito.mock(...)` and wiring the class under test through its constructor. That needs no initializer at all, and some teams prefer it for exactly that reason. The annotation route buys concision and mock naming; the manual route buys explicitness. ## Interview framing Say it in one sentence — the annotation is inert until an initializer processes it — then name the three initializers and the two classic traps (JUnit 4 runner under Jupiter, mixed imports). That is the complete answer.

  • A test class carries @RunWith(MockitoJUnitRunner.class) but the mocks are still null. What is going on?
    The class is almost certainly being executed by JUnit 5, which does not understand `@RunWith` and ignores it without warning, so nothing ever initializes the annotated fields. Check whether the test methods import `org.junit.jupiter.api.Test`. The fix is to replace the runner with `@ExtendWith(MockitoExtension.class)` and make all lifecycle annotations Jupiter ones.
  • Is it harmful to both register the Mockito JUnit 5 extension and call openMocks(this) in @BeforeEach?
    Yes, though not always visibly. The fields are populated twice and the second set overwrites the first, so any stubbing performed between the two initializations is silently discarded, and you now have two overlapping mocking sessions to validate. Choose one mechanism per class; put it in the base class if several classes need it.

saying these in an interview costs you the question

  • Believing the @Mock annotation alone creates the mock
  • Leaving a JUnit 4 @RunWith or @Rule on a JUnit 5 test class and expecting it to work
  • Mixing org.junit.Test with @BeforeEach and wondering why setup never ran
  • Calling openMocks in a static @BeforeAll and expecting instance fields to be set
  • Registering both the extension and openMocks 'to be safe'

context

open as a page

Compare registering Mockito's JUnit 5 extension with calling MockitoAnnotations.openMocks(this) in a setup method: what does the extension give you that the manual call does not, and when would you still choose the manual call?

level: middleimportance: must knowfreq 50%

basics

~20 s

Both create the annotated mocks per test. The extension additionally applies strict stubs (failing on unused or mismatched stubbings), validates Mockito usage after each test, closes the session for you, and can inject mocks as test-method parameters. openMocks does none of that but works in any framework and needs no extra artifact.

open as a page

MockitoAnnotations.openMocks(this) returns an AutoCloseable. What does closing it do, what goes wrong in a large suite if you never close it, and how does it differ from the older initMocks call?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Closing ends that mocking session and releases the mocks Mockito is holding. With the inline mock maker every mock is kept in a global registry until released, so never closing means mocks and everything they captured stay reachable across thousands of tests — growing memory, sometimes to OutOfMemoryError. initMocks returned nothing, which is why it was deprecated in favour of openMocks.

open as a page

In an older Java codebase you find one test class using @RunWith(MockitoJUnitRunner.class) and another declaring a MockitoRule field. What does each do, why would a team pick the rule, and what happens to both when the class is moved to JUnit 5?

level: middleimportance: nice to knowfreq 26%

basics

~20 s

Both are JUnit 4 Mockito integrations: they initialize annotated mocks, validate Mockito usage after each test, and by default detect unused stubbings. The rule exists because a class can have only one runner, so the rule leaves that slot free for another runner. Under JUnit 5 both are ignored silently, leaving mocks null.

open as a page