Mockito mock objects library core API and implementation for comprehensive Java unit testing
—
This section covers advanced mocking capabilities introduced in Mockito 3.4+ for mocking static methods and object construction.
Mock static methods within a controlled scope.
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock)
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, String name)
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, Answer defaultAnswer)
public static <T> MockedStatic<T> mockStatic(Class<T> classToMock, MockSettings settings)
interface MockedStatic<T> extends AutoCloseable {
<S> OngoingStubbing<S> when(Verification verification);
<S> void verify(Verification verification);
void verify(Verification verification, VerificationMode mode);
void verifyNoMoreInteractions();
void verifyNoInteractions();
void clearInvocations();
void close();
void closeOnDemand();
boolean isClosed();
}Usage Examples:
// Basic static mocking
@Test
void testStaticMethod() {
try (MockedStatic<Math> mockedMath = mockStatic(Math.class)) {
// Stub static method
mockedMath.when(() -> Math.max(1, 2)).thenReturn(5);
// Use static method
int result = Math.max(1, 2);
assertEquals(5, result);
// Verify static method call
mockedMath.verify(() -> Math.max(1, 2));
}
// Static mock automatically closed
}
// Static mocking with argument matchers
@Test
void testStaticWithMatchers() {
try (MockedStatic<Files> mockedFiles = mockStatic(Files.class)) {
mockedFiles.when(() -> Files.exists(any(Path.class)))
.thenReturn(true);
boolean exists = Files.exists(Paths.get("/any/path"));
assertTrue(exists);
mockedFiles.verify(() -> Files.exists(any(Path.class)));
}
}Mock only specific static methods while keeping others unchanged.
@Test
void testPartialStaticMocking() {
try (MockedStatic<StringUtils> mockedUtils = mockStatic(StringUtils.class, CALLS_REAL_METHODS)) {
// Only mock specific method
mockedUtils.when(() -> StringUtils.isEmpty("test")).thenReturn(true);
// This calls the real method
String result = StringUtils.capitalize("hello");
assertEquals("Hello", result);
// This calls the mocked method
boolean isEmpty = StringUtils.isEmpty("test");
assertTrue(isEmpty);
}
}Mock object construction and initialization.
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock)
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, Function<Context, MockSettings> settingsFactory)
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, MockInitializer<T> mockInitializer)
public static <T> MockedConstruction<T> mockConstruction(Class<T> classToMock, Function<Context, MockSettings> settingsFactory, MockInitializer<T> mockInitializer)
interface MockedConstruction<T> extends AutoCloseable {
List<T> constructed();
void close();
boolean isClosed();
interface Context {
int getCount();
Class<?> getConstructedType();
List<Class<?>> getParameterTypes();
List<Object> getArguments();
}
interface MockInitializer<T> {
void prepare(T mock, Context context) throws Throwable;
}
}Usage Examples:
// Basic construction mocking
@Test
void testConstructionMocking() {
try (MockedConstruction<EmailService> mockedConstruction =
mockConstruction(EmailService.class)) {
// Create objects - they will be mocked
EmailService service1 = new EmailService("config1");
EmailService service2 = new EmailService("config2");
// Get constructed mocks
List<EmailService> constructed = mockedConstruction.constructed();
assertEquals(2, constructed.size());
// Configure behavior
when(service1.sendEmail(any())).thenReturn(true);
when(service2.sendEmail(any())).thenReturn(false);
// Test behavior
assertTrue(service1.sendEmail("test"));
assertFalse(service2.sendEmail("test"));
}
}
// Construction mocking with initialization
@Test
void testConstructionWithInitializer() {
try (MockedConstruction<DatabaseConnection> mockedConstruction =
mockConstruction(DatabaseConnection.class, (mock, context) -> {
// Initialize each constructed mock
when(mock.isConnected()).thenReturn(true);
when(mock.getUrl()).thenReturn("mocked-url");
})) {
DatabaseConnection conn1 = new DatabaseConnection("real-url");
DatabaseConnection conn2 = new DatabaseConnection("another-url");
// Both connections have the same mocked behavior
assertTrue(conn1.isConnected());
assertTrue(conn2.isConnected());
assertEquals("mocked-url", conn1.getUrl());
assertEquals("mocked-url", conn2.getUrl());
}
}Context-aware construction mocking with different behaviors.
@Test
void testContextAwareConstruction() {
try (MockedConstruction<Logger> mockedConstruction =
mockConstruction(Logger.class,
context -> withSettings().name("logger-" + context.getCount()),
(mock, context) -> {
String loggerName = "Logger#" + context.getCount();
when(mock.getName()).thenReturn(loggerName);
// Different behavior based on constructor arguments
if (context.getArguments().contains("DEBUG")) {
when(mock.isDebugEnabled()).thenReturn(true);
} else {
when(mock.isDebugEnabled()).thenReturn(false);
}
})) {
Logger logger1 = new Logger("INFO");
Logger logger2 = new Logger("DEBUG");
assertEquals("Logger#1", logger1.getName());
assertEquals("Logger#2", logger2.getName());
assertFalse(logger1.isDebugEnabled());
assertTrue(logger2.isDebugEnabled());
}
}Combine different mocking approaches for comprehensive testing.
@Test
void testCombinedMocking() {
try (MockedStatic<FileUtils> mockedFileUtils = mockStatic(FileUtils.class);
MockedConstruction<FileReader> mockedConstruction =
mockConstruction(FileReader.class, (mock, context) -> {
when(mock.read()).thenReturn("mocked content");
})) {
// Mock static utility
mockedFileUtils.when(() -> FileUtils.exists("test.txt"))
.thenReturn(true);
// Code under test
FileProcessor processor = new FileProcessor();
String result = processor.processFile("test.txt");
// Verify both static and construction calls
mockedFileUtils.verify(() -> FileUtils.exists("test.txt"));
assertEquals(1, mockedConstruction.constructed().size());
FileReader constructedReader = mockedConstruction.constructed().get(0);
verify(constructedReader).read();
}
}Always use try-with-resources for automatic cleanup.
// CORRECT - automatic cleanup
@Test
void testWithTryWithResources() {
try (MockedStatic<System> mockedSystem = mockStatic(System.class)) {
mockedSystem.when(() -> System.currentTimeMillis()).thenReturn(123456L);
// Test code
} // Automatically closed
}
// INCORRECT - manual cleanup required
@Test
void testWithManualCleanup() {
MockedStatic<System> mockedSystem = mockStatic(System.class);
try {
mockedSystem.when(() -> System.currentTimeMillis()).thenReturn(123456L);
// Test code
} finally {
mockedSystem.close(); // Must remember to close
}
}Static mocks are not thread-safe and should be used carefully in parallel tests.
// Isolate static mocking in test methods
class ThreadSafeStaticTest {
@Test
void test1() {
try (MockedStatic<Math> mock = mockStatic(Math.class)) {
// Isolated static mock
}
}
@Test
void test2() {
try (MockedStatic<Math> mock = mockStatic(Math.class)) {
// Separate static mock instance
}
}
}Static and construction mocking have performance overhead.
// Use sparingly and scope appropriately
@Test
void testPerformanceAware() {
// Scope static mock to minimum necessary
String result;
try (MockedStatic<ExpensiveUtil> mock = mockStatic(ExpensiveUtil.class)) {
mock.when(() -> ExpensiveUtil.compute(any())).thenReturn("cached");
result = ExpensiveUtil.compute("input");
}
// Continue test without static mock overhead
assertEquals("cached", result);
}Understanding when static/construction mocking isn't the best solution.
// Instead of mocking static utilities
class AvoidStaticMocking {
// AVOID if possible
@Test
void testWithStaticMocking() {
try (MockedStatic<UUID> mock = mockStatic(UUID.class)) {
mock.when(UUID::randomUUID).thenReturn(fixedUuid);
// Test
}
}
// PREFER dependency injection
@Test
void testWithDependencyInjection() {
UuidGenerator mockGenerator = mock(UuidGenerator.class);
when(mockGenerator.generate()).thenReturn(fixedUuid);
MyService service = new MyService(mockGenerator);
// Test
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-mockito--mockito-core