0
# Constructor Mocking
1
2
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.
3
4
## Capabilities
5
6
### Constructor Expectation Setup by Class
7
8
Set up expectations for constructor calls on a specific class, allowing you to control what happens when new instances are created.
9
10
```java { .api }
11
static <T> ConstructorExpectationSetup<T> whenNew(Class<T> type);
12
```
13
14
**Parameters:**
15
- `type` - The class whose constructor calls should be intercepted
16
17
**Returns:** ConstructorExpectationSetup for specifying constructor arguments and return behavior
18
19
**Usage Example:**
20
```java
21
@Test
22
@PrepareForTest(FileService.class)
23
public void testConstructorMocking() throws Exception {
24
File mockFile = mock(File.class);
25
26
// Mock constructor to return mock instead of real File
27
whenNew(File.class).withArguments("test.txt").thenReturn(mockFile);
28
when(mockFile.exists()).thenReturn(true);
29
when(mockFile.length()).thenReturn(1024L);
30
31
FileService service = new FileService();
32
long size = service.getFileSize("test.txt"); // Creates new File("test.txt") internally
33
34
assertEquals(1024L, size);
35
verifyNew(File.class).withArguments("test.txt");
36
}
37
```
38
39
### Constructor Expectation by Constructor Reference
40
41
Set up expectations using a specific Constructor reflection object for type-safe constructor mocking.
42
43
```java { .api }
44
static <T> WithOrWithoutExpectedArguments<T> whenNew(Constructor<T> ctor);
45
```
46
47
**Parameters:**
48
- `ctor` - The specific Constructor object to intercept
49
50
**Returns:** Fluent interface for specifying arguments and return behavior
51
52
**Usage Example:**
53
```java
54
@Test
55
@PrepareForTest(DatabaseConnection.class)
56
public void testSpecificConstructor() throws Exception {
57
Constructor<DatabaseConnection> constructor =
58
DatabaseConnection.class.getConstructor(String.class, int.class);
59
DatabaseConnection mockConnection = mock(DatabaseConnection.class);
60
61
whenNew(constructor).withArguments("localhost", 5432).thenReturn(mockConnection);
62
when(mockConnection.isConnected()).thenReturn(true);
63
64
DatabaseService service = new DatabaseService();
65
boolean connected = service.connectToDatabase("localhost", 5432);
66
67
assertTrue(connected);
68
}
69
```
70
71
### Constructor Expectation for Inner Classes
72
73
Set up expectations for constructor calls on inner, local, or anonymous classes using their fully qualified names.
74
75
```java { .api }
76
static <T> ConstructorExpectationSetup<T> whenNew(String fullyQualifiedName) throws Exception;
77
```
78
79
**Parameters:**
80
- `fullyQualifiedName` - The fully qualified name of the inner/local/anonymous class
81
82
**Returns:** ConstructorExpectationSetup for the specified class
83
84
**Usage Example:**
85
```java
86
@Test
87
@PrepareForTest(OuterClass.class)
88
public void testInnerClassConstructor() throws Exception {
89
OuterClass.InnerClass mockInner = mock(OuterClass.InnerClass.class);
90
91
whenNew("com.example.OuterClass$InnerClass")
92
.withArguments("parameter")
93
.thenReturn(mockInner);
94
95
when(mockInner.getValue()).thenReturn("mocked inner value");
96
97
OuterClass outer = new OuterClass();
98
String result = outer.createInnerAndGetValue("parameter");
99
100
assertEquals("mocked inner value", result);
101
}
102
```
103
104
### Constructor Verification
105
106
Verify that constructors were called with expected arguments and frequencies.
107
108
```java { .api }
109
static <T> ConstructorArgumentsVerification verifyNew(Class<T> mock);
110
static <T> ConstructorArgumentsVerification verifyNew(Class<?> mock, VerificationMode mode);
111
```
112
113
**Parameters:**
114
- `mock` - The class whose constructor calls should be verified
115
- `mode` - Verification mode (times, atLeast, never, etc.)
116
117
**Returns:** ConstructorArgumentsVerification for specifying expected arguments
118
119
**Usage Example:**
120
```java
121
@Test
122
@PrepareForTest({HttpClient.class, HttpGet.class})
123
public void testConstructorVerification() throws Exception {
124
HttpClient mockClient = mock(HttpClient.class);
125
HttpGet mockGet = mock(HttpGet.class);
126
127
whenNew(HttpClient.class).withNoArguments().thenReturn(mockClient);
128
whenNew(HttpGet.class).withArguments("http://example.com").thenReturn(mockGet);
129
130
WebService service = new WebService();
131
service.makeGetRequest("http://example.com");
132
133
// Verify constructors were called
134
verifyNew(HttpClient.class).withNoArguments();
135
verifyNew(HttpGet.class).withArguments("http://example.com");
136
verifyNew(HttpGet.class, times(1)).withArguments("http://example.com");
137
}
138
```
139
140
## Constructor Expectation Interface Methods
141
142
```java { .api }
143
interface ConstructorExpectationSetup<T> extends WithOrWithoutExpectedArguments<T>, WithExpectedParameterTypes<T>, WithAnyArguments<T> {
144
}
145
146
interface WithOrWithoutExpectedArguments<T> extends WithExpectedArguments<T>, WithoutExpectedArguments<T> {
147
}
148
149
interface WithExpectedArguments<T> {
150
OngoingStubbing<T> withArguments(Object firstArgument, Object... additionalArguments) throws Exception;
151
}
152
153
interface WithoutExpectedArguments<T> {
154
OngoingStubbing<T> withNoArguments() throws Exception;
155
}
156
157
interface WithExpectedParameterTypes<T> {
158
WithExpectedArguments<T> withParameterTypes(Class<?> parameterType, Class<?>... additionalParameterTypes);
159
}
160
161
interface WithAnyArguments<T> {
162
OngoingStubbing<T> withAnyArguments() throws Exception;
163
}
164
165
interface ConstructorArgumentsVerification {
166
void withArguments(Object argument, Object... additionalArguments) throws Exception;
167
void withNoArguments() throws Exception;
168
}
169
```
170
171
## Common Patterns
172
173
### Testing Code with Hard-coded Dependencies
174
175
```java
176
@Test
177
@PrepareForTest(EmailSender.class)
178
public void testHardcodedDependencies() throws Exception {
179
SMTPClient mockSMTP = mock(SMTPClient.class);
180
181
// Mock constructor that creates SMTP connection internally
182
whenNew(SMTPClient.class)
183
.withArguments("smtp.gmail.com", 587)
184
.thenReturn(mockSMTP);
185
186
when(mockSMTP.sendMessage(anyString(), anyString(), anyString())).thenReturn(true);
187
188
EmailSender sender = new EmailSender();
189
boolean sent = sender.sendEmail("to@example.com", "subject", "body");
190
191
assertTrue(sent);
192
verify(mockSMTP).sendMessage("to@example.com", "subject", "body");
193
verifyNew(SMTPClient.class).withArguments("smtp.gmail.com", 587);
194
}
195
```
196
197
### Testing Exception Handling During Construction
198
199
```java
200
@Test
201
@PrepareForTest(FileProcessor.class)
202
public void testConstructorException() throws Exception {
203
// Mock constructor to throw exception
204
whenNew(BufferedReader.class)
205
.withArguments(any(FileReader.class))
206
.thenThrow(new IOException("File not found"));
207
208
FileProcessor processor = new FileProcessor();
209
210
// Test that the code handles constructor exception properly
211
assertThrows(ProcessingException.class, () -> {
212
processor.processFile("nonexistent.txt");
213
});
214
215
verifyNew(BufferedReader.class).withArguments(any(FileReader.class));
216
}
217
```
218
219
### Testing Object Factory Patterns
220
221
```java
222
@Test
223
@PrepareForTest(ConnectionFactory.class)
224
public void testFactoryPattern() throws Exception {
225
Connection mockConnection = mock(Connection.class);
226
227
// Mock the internal object creation in factory
228
whenNew(PostgreSQLConnection.class)
229
.withArguments(anyString(), anyInt(), anyString(), anyString())
230
.thenReturn(mockConnection);
231
232
when(mockConnection.isValid(anyInt())).thenReturn(true);
233
234
ConnectionFactory factory = new ConnectionFactory();
235
Connection connection = factory.createConnection("postgresql://localhost:5432/testdb");
236
237
assertTrue(connection.isValid(5));
238
verifyNew(PostgreSQLConnection.class)
239
.withArguments("localhost", 5432, "testdb", anyString());
240
}
241
```
242
243
### Constructor Mocking with Parameter Type Matching
244
245
```java
246
@Test
247
@PrepareForTest(DocumentProcessor.class)
248
public void testParameterTypeMatching() throws Exception {
249
Document mockDocument = mock(Document.class);
250
251
// Use parameter type matching when argument values are complex
252
whenNew(Document.class)
253
.withParameterTypes(InputStream.class, String.class)
254
.withArguments(any(InputStream.class), eq("UTF-8"))
255
.thenReturn(mockDocument);
256
257
when(mockDocument.getContent()).thenReturn("mocked content");
258
259
DocumentProcessor processor = new DocumentProcessor();
260
String content = processor.parseDocument(inputStream, "UTF-8");
261
262
assertEquals("mocked content", content);
263
}
264
```
265
266
### Mocking Constructor with Any Arguments
267
268
```java
269
@Test
270
@PrepareForTest(LoggerFactory.class)
271
public void testAnyArguments() throws Exception {
272
Logger mockLogger = mock(Logger.class);
273
274
// Accept any arguments to constructor
275
whenNew(FileLogger.class).withAnyArguments().thenReturn(mockLogger);
276
277
LoggerFactory factory = new LoggerFactory();
278
Logger logger = factory.createLogger("any-name", "any-path", LogLevel.INFO);
279
280
assertEquals(mockLogger, logger);
281
verifyNew(FileLogger.class).withArguments("any-name", "any-path", LogLevel.INFO);
282
}
283
```
284
285
## Requirements
286
287
- Classes whose constructors are mocked must be specified in `@PrepareForTest` annotation
288
- Test must use `@RunWith(PowerMockRunner.class)` or equivalent
289
- Constructor expectations must be set up before the code under test executes
290
- Constructor mocking only intercepts calls to `new` - reflection-based construction is not intercepted
291
- Inner class constructor mocking requires the outer class in `@PrepareForTest`