This is an issue when a test class field is initialized using a manual mock creation method while the class is annotated with a testing framework extension that automatically initializes mocks.
In Java with Mockito, this specifically occurs when using the mock() method for field initialization in a class annotated with
@ExtendWith(MockitoExtension.class) (JUnit 5) or @RunWith(MockitoJUnitRunner.class) (JUnit 4).
When you use the testing framework’s test runner or extension, it automatically processes mock annotations in your test class. This means you can declare mocks using annotations instead of manually calling the mock creation function.
Using mock annotations has several advantages:
Strict stubbing is a valuable feature that helps maintain test quality:
The mock creation function is still appropriate for creating ad-hoc mocks inside test method bodies, where you need a mock for just one specific test case. But for field-level mocks that multiple tests might use, annotations are the better choice.
Using programmatic mock creation methods for field initialization instead of declarative mock annotations makes tests harder to maintain and can hide quality issues. Without automatic validation of mock usage, unnecessary or unused mocks can accumulate over time, making tests slower to understand and update. The test suite becomes less reliable at catching setup mistakes or outdated test code.
For JUnit 4 tests using MockitoJUnitRunner, replace the field initialization with the @Mock annotation.
@RunWith(MockitoJUnitRunner.class)
public class OrderProcessorTest {
private final PaymentService paymentService = mock(PaymentService.class); // Noncompliant
private final NotificationService notificationService = mock(NotificationService.class); // Noncompliant
@Test
public void testProcessOrder() {
// test logic...
}
}
@RunWith(MockitoJUnitRunner.class)
public class OrderProcessorTest {
@Mock
private PaymentService paymentService;
@Mock
private NotificationService notificationService;
@Test
public void testProcessOrder() {
// test logic...
}
}
For JUnit 5 tests using MockitoExtension, replace the field initialization with the @Mock annotation. Note that ad-hoc mocks created
inside test methods can still use mock() - this rule only applies to field declarations.
@ExtendWith(MockitoExtension.class)
class DataProcessorTest {
private final DataSource dataSource = mock(DataSource.class); // Noncompliant
@Test
void testProcessData() {
// This ad-hoc mock inside a method is fine
DataValidator validator = mock(DataValidator.class);
when(dataSource.getData()).thenReturn(someData);
// test logic...
}
}
@ExtendWith(MockitoExtension.class)
class DataProcessorTest {
@Mock
private DataSource dataSource;
@Test
void testProcessData() {
// This ad-hoc mock inside a method is fine
DataValidator validator = mock(DataValidator.class);
when(dataSource.getData()).thenReturn(someData);
// test logic...
}
}