After migrating to JDK 17 and Mockito 4.9.0, I cannot use @SuppressStaticInitializationFor, but I need to prevent some classes from being initialized statically.
Example test:
@RunWith(MockitoJUnitRunner.class)
public class TaskManagerTest {
@Before
public void setUp(){
Mockito.mockStatic(NonWorkingDayHelper.class);
Mockito.mockStatic(TaskService.class);
}
@Test
public void testUpdateSLARemainInDays() throws Exception {
Mockito.when(NonWorkingDayHelper.isNonWorkingDay(any(Date.class))).thenReturn(false);
Mockito.when(TaskService.getInstance()).thenReturn(Mockito.mock(TaskService.class));
TaskManager.updateSLARemainInDays();
}
}
Error encountered:
Cannot instrument class XXX because it or one of its supertypes could not be initialized
Is there an alternative in Mockito 4.x to achieve the same effect as @SuppressStaticInitializationFor?
I ran into the same problem when migrating tests from Mockito 2/3 to 4.x on JDK 17.
Mockito removed @SuppressStaticInitializationFor, so you can no longer prevent static initializers at the annotation level.
In Mockito 4, the workaround is to mock static methods dynamically using mockStatic(), but you need to do it before the class is ever loaded by the JVM.
For example:
try (MockedStatic<NonWorkingDayHelper> helperMock = Mockito.mockStatic(NonWorkingDayHelper.class);
MockedStatic<TaskService> serviceMock = Mockito.mockStatic(TaskService.class)) {
helperMock.when(() -> NonWorkingDayHelper.isNonWorkingDay(any(Date.class))).thenReturn(false);
TaskService mockService = Mockito.mock(TaskService.class);
serviceMock.when(TaskService::getInstance).thenReturn(mockService);
TaskManager.updateSLARemainInDays();
}
This ensures the classes are mocked before their static initializers run.
In my experience, any previous references to the class (even imports in other code) can trigger initialization, so it’s crucial to avoid touching the class before mockStatic().
I had this exact issue after upgrading to JDK 17 + Mockito 4.
What worked for me is wrapping all static mocking inside a try-with-resources block, which guarantees the static initializer is effectively “replaced” for the duration of the test.
try (MockedStatic<NonWorkingDayHelper> nh = Mockito.mockStatic(NonWorkingDayHelper.class)) {
nh.when(() -> NonWorkingDayHelper.isNonWorkingDay(any())).thenReturn(false);
// call code that would trigger the static initializer
}
If you try to call mockStatic() after the class has already been loaded (maybe by another test or a field reference), you’ll get the “cannot be initialized” error.
I now put all my static mocks inside the test method instead of using @Before or class-level static mocks, and it solved the problem consistently.
After migrating to Mockito 4, I realized @SuppressStaticInitializationFor is gone, so you can’t rely on that anymore.
The trick I use is avoiding touching the class until you mock it.
Some tips that helped me:
Don’t reference the class in @Before or as a field initializer.
Use try-with-resources to mock the static class at the point of use.
If the class has complex static initialization that can’t be avoided, consider refactoring the static logic into instance methods or using a wrapper you can mock instead.
For example:
@Test
void testSomething() {
try (MockedStatic<NonWorkingDayHelper> helper = Mockito.mockStatic(NonWorkingDayHelper.class)) {
helper.when(() -> NonWorkingDayHelper.isNonWorkingDay(any())).thenReturn(false);
// your test code here
}
}
This approach avoids the cannot be initialized error, and I’ve been able to migrate most of my legacy tests without changing production code.