Uninitialized Mockito Annotation

ID

java.annotated_mockito_objects_init

Severity

critical

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Java

Tags

mockito, reliability, testing

Description

Reports a class whose @Mock, @Spy, @Captor or @InjectMocks fields are never initialized by any of Mockito’s supported triggers.

Rationale

Unlike Mockito.mock(…​) or Mockito.spy(…​), the annotations do nothing by themselves. Without a trigger, every annotated field stays null: a call on it throws NullPointerException, and a test that happens not to touch the field passes while verifying nothing real.

class BillingServiceTest {
  @Mock private PaymentGateway gateway;
  @InjectMocks private BillingService serviceUnderTest;

  @Test
  void chargesTheGateway() {
    serviceUnderTest.charge(100);
  }
}

Remediation

Pick one of Mockito’s initialization triggers: a JUnit 4 runner, a JUnit 5 extension, a @Rule, or an explicit MockitoAnnotations.openMocks(this) call from a setup method, a constructor or an instance initializer block.

@ExtendWith(MockitoExtension.class)
class BillingServiceTest {
  @Mock private PaymentGateway gateway;
  @InjectMocks private BillingService serviceUnderTest;

  @Test
  void chargesTheGateway() {
    serviceUnderTest.charge(100);
  }
}

What is not reported

Only the first annotated field is reported — the rest share the same missing trigger, and only fields left for the annotation to fill in count: a field assigned at its declaration (@Spy Foo foo = spy(new Foo()), @InjectMocks Service s = new Service()) is a real object whatever the annotation does, and is never reported.

MockitoAnnotations.openMocks(this) / initMocks(this) counts wherever a class can legitimately run it before its tests: a @Before/@BeforeEach method, a constructor, or an instance initializer block. The constructor form is how a private per-test "context" holder initializes its own mocks.

A @RunWith(…​) or @ExtendWith(…​) is accepted regardless of the argument, since verifying what a third-party runner or extension actually does at test time is out of scope. A @Nested class inherits its enclosing class’s trigger. A subclass inherits its superclass’s trigger: a superclass in the same file is checked in full, and a superclass in another file is resolved through the project-wide software model, which answers for its class-level annotations. When the extends clause names a type the model does not know at all, the class is left unreported rather than guessed at.

A trigger reached only through a custom, meta-annotated annotation, or through a @Rule field or an openMocks call declared on a superclass in another file (the model holds no method bodies), is not detected.

© 2026 Xygeni. All rights reserved