0
# Test Execution
1
2
Test execution infrastructure providing contexts, listeners, and result reporting for test engines. This system enables engines to execute discovered tests and communicate results back to the platform.
3
4
## Capabilities
5
6
### ExecutionRequest
7
8
Provides test engines with everything needed to execute discovered tests, including the test descriptor tree, execution listener, configuration, and test-scoped storage.
9
10
```java { .api }
11
/**
12
* Request object providing context and resources for test execution.
13
*/
14
public final class ExecutionRequest {
15
/**
16
* Get the root test descriptor to execute.
17
* @return root test descriptor containing test hierarchy
18
*/
19
public TestDescriptor getRootTestDescriptor();
20
21
/**
22
* Get the engine execution listener for reporting test events.
23
* @return execution listener for this request
24
*/
25
public EngineExecutionListener getEngineExecutionListener();
26
27
/**
28
* Get configuration parameters for test execution.
29
* @return configuration parameters
30
*/
31
public ConfigurationParameters getConfigurationParameters();
32
33
/**
34
* Get the output directory provider for file outputs.
35
* @return output directory provider
36
*/
37
public OutputDirectoryProvider getOutputDirectoryProvider();
38
39
/**
40
* Get the request-scoped hierarchical store.
41
* @return namespaced hierarchical store for request-scoped data
42
*/
43
public NamespacedHierarchicalStore<Namespace> getStore();
44
}
45
```
46
47
**Usage Example:**
48
49
```java
50
@Override
51
public void execute(ExecutionRequest request) {
52
TestDescriptor rootDescriptor = request.getRootTestDescriptor();
53
EngineExecutionListener listener = request.getEngineExecutionListener();
54
ConfigurationParameters config = request.getConfigurationParameters();
55
56
// Start execution of root descriptor
57
listener.executionStarted(rootDescriptor);
58
59
try {
60
// Execute all child descriptors
61
for (TestDescriptor child : rootDescriptor.getChildren()) {
62
executeDescriptor(child, listener, config);
63
}
64
listener.executionFinished(rootDescriptor, TestExecutionResult.successful());
65
} catch (Exception e) {
66
listener.executionFinished(rootDescriptor, TestExecutionResult.failed(e));
67
}
68
}
69
```
70
71
### EngineExecutionListener Interface
72
73
Listener interface for receiving test execution events and results. Test engines use this to communicate execution progress and outcomes.
74
75
```java { .api }
76
/**
77
* Listener for test execution events, enabling engines to report progress and results.
78
*/
79
public interface EngineExecutionListener {
80
/**
81
* Called when a dynamic test is registered during execution.
82
* @param testDescriptor the dynamically registered test descriptor
83
*/
84
void dynamicTestRegistered(TestDescriptor testDescriptor);
85
86
/**
87
* Called when execution of a test or container is skipped.
88
* @param testDescriptor the skipped test descriptor
89
* @param reason the reason for skipping
90
*/
91
void executionSkipped(TestDescriptor testDescriptor, String reason);
92
93
/**
94
* Called when execution of a test or container starts.
95
* @param testDescriptor the test descriptor being executed
96
*/
97
void executionStarted(TestDescriptor testDescriptor);
98
99
/**
100
* Called when execution of a test or container finishes.
101
* @param testDescriptor the test descriptor that finished
102
* @param testExecutionResult the execution result
103
*/
104
void executionFinished(TestDescriptor testDescriptor, TestExecutionResult testExecutionResult);
105
106
/**
107
* Called when a reporting entry is published during test execution.
108
* @param testDescriptor the test descriptor publishing the entry
109
* @param entry the report entry with key-value data
110
*/
111
void reportingEntryPublished(TestDescriptor testDescriptor, ReportEntry entry);
112
113
/**
114
* Called when a file entry is published during test execution.
115
* @param testDescriptor the test descriptor publishing the file
116
* @param fileEntry the file entry attachment
117
*/
118
void fileEntryPublished(TestDescriptor testDescriptor, FileEntry fileEntry);
119
120
/**
121
* No-operation listener implementation.
122
*/
123
EngineExecutionListener NOOP = new EngineExecutionListener() {
124
// All methods have empty implementations
125
};
126
}
127
```
128
129
**Usage Example:**
130
131
```java
132
private void executeTest(TestDescriptor testDescriptor, EngineExecutionListener listener) {
133
listener.executionStarted(testDescriptor);
134
135
try {
136
// Execute the actual test logic
137
Object testInstance = createTestInstance(testDescriptor);
138
Method testMethod = getTestMethod(testDescriptor);
139
140
// Publish reporting entry before execution
141
ReportEntry entry = ReportEntry.from("phase", "execution");
142
listener.reportingEntryPublished(testDescriptor, entry);
143
144
// Execute test method
145
testMethod.invoke(testInstance);
146
147
// Report successful completion
148
listener.executionFinished(testDescriptor, TestExecutionResult.successful());
149
150
} catch (AssertionError e) {
151
// Test failed
152
listener.executionFinished(testDescriptor, TestExecutionResult.failed(e));
153
} catch (Exception e) {
154
// Test aborted due to unexpected error
155
listener.executionFinished(testDescriptor, TestExecutionResult.aborted(e));
156
}
157
}
158
```
159
160
### Reporting Infrastructure
161
162
Classes for publishing structured reporting data and file attachments during test execution.
163
164
```java { .api }
165
/**
166
* Time-stamped key-value pairs for structured reporting during test execution.
167
*/
168
public final class ReportEntry {
169
/**
170
* Create a report entry from a map of key-value pairs.
171
* @param keyValuePairs map of keys to values
172
* @return ReportEntry with current timestamp
173
*/
174
public static ReportEntry from(Map<String, String> keyValuePairs);
175
176
/**
177
* Create a report entry from a single key-value pair.
178
* @param key the report key
179
* @param value the report value
180
* @return ReportEntry with current timestamp
181
*/
182
public static ReportEntry from(String key, String value);
183
184
/**
185
* Get the key-value pairs for this report entry.
186
* @return unmodifiable map of key-value pairs
187
*/
188
public Map<String, String> getKeyValuePairs();
189
190
/**
191
* Get the timestamp when this entry was created.
192
* @return creation timestamp
193
*/
194
public LocalDateTime getTimestamp();
195
}
196
197
/**
198
* File attachment for test execution reporting.
199
*/
200
public final class FileEntry {
201
/**
202
* Create a file entry from a path and media type.
203
* @param path path to the file
204
* @param mediaType media type of the file
205
* @return FileEntry instance
206
*/
207
public static FileEntry from(Path path, String mediaType);
208
209
/**
210
* Create a file entry from a path with content type detection.
211
* @param path path to the file
212
* @return FileEntry with detected media type
213
*/
214
public static FileEntry from(Path path);
215
216
/**
217
* Get the file path.
218
* @return path to the file
219
*/
220
public Path getPath();
221
222
/**
223
* Get the media type.
224
* @return media type of the file
225
*/
226
public String getMediaType();
227
}
228
```
229
230
**Usage Example:**
231
232
```java
233
// Publish structured reporting data
234
Map<String, String> data = Map.of(
235
"test.type", "integration",
236
"database.url", "jdbc:h2:mem:test",
237
"execution.time", "1.234s"
238
);
239
ReportEntry entry = ReportEntry.from(data);
240
listener.reportingEntryPublished(testDescriptor, entry);
241
242
// Publish file attachments
243
Path screenshotPath = captureScreenshot();
244
FileEntry fileEntry = FileEntry.from(screenshotPath, "image/png");
245
listener.fileEntryPublished(testDescriptor, fileEntry);
246
```
247
248
### Output Directory Provider
249
250
Interface for providing output directories where test engines can write files during execution.
251
252
```java { .api }
253
/**
254
* Provider for output directories where test engines can write execution artifacts.
255
*/
256
public interface OutputDirectoryProvider {
257
/**
258
* Get the default output directory for the current test execution.
259
* @return path to the default output directory
260
*/
261
Path getDefaultOutputDirectory();
262
263
/**
264
* Get a subdirectory within the default output directory.
265
* @param subdirectoryName name of the subdirectory
266
* @return path to the subdirectory (created if necessary)
267
*/
268
Path getOutputDirectory(String subdirectoryName);
269
270
/**
271
* Get an output directory for a specific test descriptor.
272
* @param testDescriptor the test descriptor
273
* @param subdirectoryName optional subdirectory name
274
* @return path to the output directory for the test
275
*/
276
Path getOutputDirectory(TestDescriptor testDescriptor, String subdirectoryName);
277
}
278
```
279
280
### Dynamic Test Registration
281
282
Support for registering tests dynamically during execution, enabling parameterized and data-driven test patterns.
283
284
**Usage Example:**
285
286
```java
287
// In a test engine's execute method
288
private void executeDynamicContainer(TestDescriptor containerDescriptor,
289
EngineExecutionListener listener) {
290
listener.executionStarted(containerDescriptor);
291
292
// Generate dynamic tests based on data
293
List<TestData> testData = loadTestData();
294
295
for (TestData data : testData) {
296
// Create dynamic test descriptor
297
UniqueId dynamicId = containerDescriptor.getUniqueId()
298
.append("dynamic", data.getName());
299
TestDescriptor dynamicTest = createDynamicTestDescriptor(dynamicId, data);
300
301
// Register dynamic test
302
containerDescriptor.addChild(dynamicTest);
303
listener.dynamicTestRegistered(dynamicTest);
304
305
// Execute the dynamic test
306
executeDynamicTest(dynamicTest, data, listener);
307
}
308
309
listener.executionFinished(containerDescriptor, TestExecutionResult.successful());
310
}
311
```
312
313
### Configuration Integration
314
315
Integration with the configuration system for accessing execution parameters.
316
317
**Usage Example:**
318
319
```java
320
@Override
321
public void execute(ExecutionRequest request) {
322
ConfigurationParameters config = request.getConfigurationParameters();
323
324
// Get configuration values
325
boolean parallelExecution = config.getBoolean("junit.jupiter.execution.parallel.enabled")
326
.orElse(false);
327
328
int timeout = config.get("test.timeout", Integer::parseInt)
329
.orElse(30);
330
331
String environment = config.get("test.environment")
332
.orElse("development");
333
334
// Use configuration in execution logic
335
if (parallelExecution) {
336
executeInParallel(request);
337
} else {
338
executeSequentially(request);
339
}
340
}
341
```