CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-powermock--powermock-api-mockito

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

Pending
Overview
Eval results
Files

constructor-mocking.mddocs/

Constructor Mocking

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.

Capabilities

Constructor Expectation Setup by Class

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 intercepted

Returns: 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");
}

Constructor Expectation by Constructor Reference

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 intercept

Returns: 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);
}

Constructor Expectation for Inner Classes

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 class

Returns: 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);
}

Constructor Verification

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 verified
  • mode - 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");
}

Constructor Expectation Interface Methods

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;
}

Common Patterns

Testing Code with Hard-coded Dependencies

@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);
}

Testing Exception Handling During Construction

@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));
}

Testing Object Factory Patterns

@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());
}

Constructor Mocking with Parameter Type Matching

@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);
}

Mocking Constructor with Any Arguments

@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);
}

Requirements

  • Classes whose constructors are mocked must be specified in @PrepareForTest annotation
  • Test must use @RunWith(PowerMockRunner.class) or equivalent
  • Constructor expectations must be set up before the code under test executes
  • Constructor mocking only intercepts calls to new - reflection-based construction is not intercepted
  • Inner class constructor mocking requires the outer class in @PrepareForTest

Install with Tessl CLI

npx tessl i tessl/maven-org-powermock--powermock-api-mockito

docs

advanced-stubbing.md

constructor-mocking.md

index.md

object-mocking.md

private-methods.md

static-mocking.md

static-verification.md

verification-extensions.md

tile.json