PowerMock API extension for Mockito that enables mocking of static methods, constructors, final classes and methods, private methods, and advanced testing capabilities through bytecode manipulation and custom classloading
—
PowerMock enables mocking constructor calls to control object creation, allowing you to test code that creates objects internally without dependency injection. This is essential for testing legacy code that creates dependencies directly rather than accepting them as parameters.
Set up expectations for constructor calls on a specific class, allowing you to control what happens when new instances are created.
static <T> ConstructorExpectationSetup<T> whenNew(Class<T> type);Parameters:
type - The class whose constructor calls should be interceptedReturns: ConstructorExpectationSetup for specifying constructor arguments and return behavior
Usage Example:
@Test
@PrepareForTest(FileService.class)
public void testConstructorMocking() throws Exception {
File mockFile = mock(File.class);
// Mock constructor to return mock instead of real File
whenNew(File.class).withArguments("test.txt").thenReturn(mockFile);
when(mockFile.exists()).thenReturn(true);
when(mockFile.length()).thenReturn(1024L);
FileService service = new FileService();
long size = service.getFileSize("test.txt"); // Creates new File("test.txt") internally
assertEquals(1024L, size);
verifyNew(File.class).withArguments("test.txt");
}Set up expectations using a specific Constructor reflection object for type-safe constructor mocking.
static <T> WithOrWithoutExpectedArguments<T> whenNew(Constructor<T> ctor);Parameters:
ctor - The specific Constructor object to interceptReturns: Fluent interface for specifying arguments and return behavior
Usage Example:
@Test
@PrepareForTest(DatabaseConnection.class)
public void testSpecificConstructor() throws Exception {
Constructor<DatabaseConnection> constructor =
DatabaseConnection.class.getConstructor(String.class, int.class);
DatabaseConnection mockConnection = mock(DatabaseConnection.class);
whenNew(constructor).withArguments("localhost", 5432).thenReturn(mockConnection);
when(mockConnection.isConnected()).thenReturn(true);
DatabaseService service = new DatabaseService();
boolean connected = service.connectToDatabase("localhost", 5432);
assertTrue(connected);
}Set up expectations for constructor calls on inner, local, or anonymous classes using their fully qualified names.
static <T> ConstructorExpectationSetup<T> whenNew(String fullyQualifiedName) throws Exception;Parameters:
fullyQualifiedName - The fully qualified name of the inner/local/anonymous classReturns: ConstructorExpectationSetup for the specified class
Usage Example:
@Test
@PrepareForTest(OuterClass.class)
public void testInnerClassConstructor() throws Exception {
OuterClass.InnerClass mockInner = mock(OuterClass.InnerClass.class);
whenNew("com.example.OuterClass$InnerClass")
.withArguments("parameter")
.thenReturn(mockInner);
when(mockInner.getValue()).thenReturn("mocked inner value");
OuterClass outer = new OuterClass();
String result = outer.createInnerAndGetValue("parameter");
assertEquals("mocked inner value", result);
}Verify that constructors were called with expected arguments and frequencies.
static <T> ConstructorArgumentsVerification verifyNew(Class<T> mock);
static <T> ConstructorArgumentsVerification verifyNew(Class<?> mock, VerificationMode mode);Parameters:
mock - The class whose constructor calls should be verifiedmode - Verification mode (times, atLeast, never, etc.)Returns: ConstructorArgumentsVerification for specifying expected arguments
Usage Example:
@Test
@PrepareForTest({HttpClient.class, HttpGet.class})
public void testConstructorVerification() throws Exception {
HttpClient mockClient = mock(HttpClient.class);
HttpGet mockGet = mock(HttpGet.class);
whenNew(HttpClient.class).withNoArguments().thenReturn(mockClient);
whenNew(HttpGet.class).withArguments("http://example.com").thenReturn(mockGet);
WebService service = new WebService();
service.makeGetRequest("http://example.com");
// Verify constructors were called
verifyNew(HttpClient.class).withNoArguments();
verifyNew(HttpGet.class).withArguments("http://example.com");
verifyNew(HttpGet.class, times(1)).withArguments("http://example.com");
}interface ConstructorExpectationSetup<T> extends WithOrWithoutExpectedArguments<T>, WithExpectedParameterTypes<T>, WithAnyArguments<T> {
}
interface WithOrWithoutExpectedArguments<T> extends WithExpectedArguments<T>, WithoutExpectedArguments<T> {
}
interface WithExpectedArguments<T> {
OngoingStubbing<T> withArguments(Object firstArgument, Object... additionalArguments) throws Exception;
}
interface WithoutExpectedArguments<T> {
OngoingStubbing<T> withNoArguments() throws Exception;
}
interface WithExpectedParameterTypes<T> {
WithExpectedArguments<T> withParameterTypes(Class<?> parameterType, Class<?>... additionalParameterTypes);
}
interface WithAnyArguments<T> {
OngoingStubbing<T> withAnyArguments() throws Exception;
}
interface ConstructorArgumentsVerification {
void withArguments(Object argument, Object... additionalArguments) throws Exception;
void withNoArguments() throws Exception;
}@Test
@PrepareForTest(EmailSender.class)
public void testHardcodedDependencies() throws Exception {
SMTPClient mockSMTP = mock(SMTPClient.class);
// Mock constructor that creates SMTP connection internally
whenNew(SMTPClient.class)
.withArguments("smtp.gmail.com", 587)
.thenReturn(mockSMTP);
when(mockSMTP.sendMessage(anyString(), anyString(), anyString())).thenReturn(true);
EmailSender sender = new EmailSender();
boolean sent = sender.sendEmail("to@example.com", "subject", "body");
assertTrue(sent);
verify(mockSMTP).sendMessage("to@example.com", "subject", "body");
verifyNew(SMTPClient.class).withArguments("smtp.gmail.com", 587);
}@Test
@PrepareForTest(FileProcessor.class)
public void testConstructorException() throws Exception {
// Mock constructor to throw exception
whenNew(BufferedReader.class)
.withArguments(any(FileReader.class))
.thenThrow(new IOException("File not found"));
FileProcessor processor = new FileProcessor();
// Test that the code handles constructor exception properly
assertThrows(ProcessingException.class, () -> {
processor.processFile("nonexistent.txt");
});
verifyNew(BufferedReader.class).withArguments(any(FileReader.class));
}@Test
@PrepareForTest(ConnectionFactory.class)
public void testFactoryPattern() throws Exception {
Connection mockConnection = mock(Connection.class);
// Mock the internal object creation in factory
whenNew(PostgreSQLConnection.class)
.withArguments(anyString(), anyInt(), anyString(), anyString())
.thenReturn(mockConnection);
when(mockConnection.isValid(anyInt())).thenReturn(true);
ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.createConnection("postgresql://localhost:5432/testdb");
assertTrue(connection.isValid(5));
verifyNew(PostgreSQLConnection.class)
.withArguments("localhost", 5432, "testdb", anyString());
}@Test
@PrepareForTest(DocumentProcessor.class)
public void testParameterTypeMatching() throws Exception {
Document mockDocument = mock(Document.class);
// Use parameter type matching when argument values are complex
whenNew(Document.class)
.withParameterTypes(InputStream.class, String.class)
.withArguments(any(InputStream.class), eq("UTF-8"))
.thenReturn(mockDocument);
when(mockDocument.getContent()).thenReturn("mocked content");
DocumentProcessor processor = new DocumentProcessor();
String content = processor.parseDocument(inputStream, "UTF-8");
assertEquals("mocked content", content);
}@Test
@PrepareForTest(LoggerFactory.class)
public void testAnyArguments() throws Exception {
Logger mockLogger = mock(Logger.class);
// Accept any arguments to constructor
whenNew(FileLogger.class).withAnyArguments().thenReturn(mockLogger);
LoggerFactory factory = new LoggerFactory();
Logger logger = factory.createLogger("any-name", "any-path", LogLevel.INFO);
assertEquals(mockLogger, logger);
verifyNew(FileLogger.class).withArguments("any-name", "any-path", LogLevel.INFO);
}@PrepareForTest annotation@RunWith(PowerMockRunner.class) or equivalentnew - reflection-based construction is not intercepted@PrepareForTestInstall with Tessl CLI
npx tessl i tessl/maven-org-powermock--powermock-api-mockito