0
# JUnit Integration
1
2
The JUnit integration provides annotation-driven configuration with automatic resource lifecycle management and test parameterization. It extends JUnit 5 with specialized extensions for connector testing.
3
4
## Capabilities
5
6
### Core Annotations
7
8
Annotations for marking test resources and configuration in test classes.
9
10
```java { .api }
11
/**
12
* Marks field defining TestEnvironment (PER-CLASS lifecycle)
13
* Only one field per test class can be annotated with @TestEnv
14
*/
15
@Target(ElementType.FIELD)
16
@Retention(RetentionPolicy.RUNTIME)
17
public @interface TestEnv {}
18
19
/**
20
* Marks field defining ExternalContextFactory (PER-CASE lifecycle)
21
* Multiple fields can be annotated for different external systems
22
*/
23
@Target(ElementType.FIELD)
24
@Retention(RetentionPolicy.RUNTIME)
25
public @interface TestContext {}
26
27
/**
28
* Marks field defining external system configuration
29
*/
30
@Target(ElementType.FIELD)
31
@Retention(RetentionPolicy.RUNTIME)
32
public @interface TestExternalSystem {}
33
34
/**
35
* Marks field defining semantic guarantees for testing
36
*/
37
@Target(ElementType.FIELD)
38
@Retention(RetentionPolicy.RUNTIME)
39
public @interface TestSemantics {}
40
```
41
42
**Usage Examples:**
43
44
```java
45
import org.apache.flink.connector.testframe.junit.annotations.*;
46
import org.apache.flink.connector.testframe.junit.extensions.ConnectorTestingExtension;
47
48
@ExtendWith(ConnectorTestingExtension.class)
49
public class MyConnectorTestSuite extends SinkTestSuiteBase<String> {
50
51
// Test environment (PER-CLASS lifecycle)
52
@TestEnv
53
MiniClusterTestEnvironment testEnv = new MiniClusterTestEnvironment();
54
55
// External context factory (PER-CASE lifecycle)
56
@TestContext
57
ExternalContextFactory<MySinkExternalContext> sinkContextFactory =
58
testName -> new MySinkExternalContext(testName);
59
60
// Multiple contexts supported
61
@TestContext
62
ExternalContextFactory<MyOtherExternalContext> otherContextFactory =
63
testName -> new MyOtherExternalContext(testName);
64
65
// External system configuration
66
@TestExternalSystem
67
MyExternalSystemConfig externalConfig = new MyExternalSystemConfig();
68
69
// Semantic configuration
70
@TestSemantics
71
List<CheckpointingMode> semantics = Arrays.asList(
72
CheckpointingMode.EXACTLY_ONCE,
73
CheckpointingMode.AT_LEAST_ONCE
74
);
75
}
76
```
77
78
### Connector Testing Extension
79
80
Main JUnit 5 extension that orchestrates the testing framework.
81
82
```java { .api }
83
/**
84
* Main JUnit 5 extension for connector testing framework
85
* Provides automatic lifecycle management and parameter injection
86
*/
87
public class ConnectorTestingExtension implements
88
BeforeAllCallback, // Initialize PER-CLASS resources
89
AfterAllCallback, // Cleanup PER-CLASS resources
90
TestTemplateInvocationContextProvider, // Provide test parameterization
91
ParameterResolver // Inject parameters into test methods
92
{
93
94
/**
95
* Initialize test environment and PER-CLASS resources
96
* Called once before all test methods in the class
97
*/
98
@Override
99
public void beforeAll(ExtensionContext context) throws Exception;
100
101
/**
102
* Cleanup test environment and PER-CLASS resources
103
* Called once after all test methods in the class
104
*/
105
@Override
106
public void afterAll(ExtensionContext context) throws Exception;
107
108
/**
109
* Provide test invocation contexts for parameterized testing
110
* Generates combinations of external contexts and semantic modes
111
*/
112
@Override
113
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context);
114
115
/**
116
* Resolve parameters for test method injection
117
* Supports TestEnvironment, ExternalContext, CheckpointingMode, ClusterControllable
118
*/
119
@Override
120
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
121
122
@Override
123
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
124
}
125
```
126
127
**Automatic Features:**
128
129
- **Resource Lifecycle**: Automatic startup/teardown of test environments
130
- **Parameter Injection**: Injects test resources into `@TestTemplate` methods
131
- **Test Parameterization**: Generates test combinations across contexts and semantics
132
- **Error Handling**: Proper cleanup even when tests fail
133
- **Parallel Execution**: Supports parallel test execution with resource isolation
134
135
### Test Case Invocation Context Provider
136
137
Provides context for individual test case invocations with proper parameter resolution.
138
139
```java { .api }
140
/**
141
* Provides test case invocation contexts with parameter resolution
142
*/
143
public class TestCaseInvocationContextProvider implements TestTemplateInvocationContextProvider {
144
145
/**
146
* Check if extension supports the test method
147
* @param context Extension context
148
* @return true if method uses @TestTemplate with supported parameters
149
*/
150
@Override
151
public boolean supportsTestTemplate(ExtensionContext context);
152
153
/**
154
* Provide invocation contexts for test template
155
* @param context Extension context
156
* @return Stream of invocation contexts for parameter combinations
157
*/
158
@Override
159
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context);
160
}
161
```
162
163
## Test Method Signatures
164
165
### Supported Parameter Types
166
167
Test methods can declare parameters that will be automatically injected:
168
169
```java { .api }
170
// Supported parameter types for @TestTemplate methods:
171
172
/**
173
* Test environment instance (PER-CLASS lifecycle)
174
*/
175
TestEnvironment testEnv
176
177
/**
178
* External context for sink testing (PER-CASE lifecycle)
179
*/
180
DataStreamSinkExternalContext<T> externalContext
181
182
/**
183
* External context for source testing (PER-CASE lifecycle)
184
*/
185
DataStreamSourceExternalContext<T> externalContext
186
187
/**
188
* Checkpointing semantic mode (injected per test variation)
189
*/
190
CheckpointingMode semantic
191
192
/**
193
* Cluster controller for failure testing (when supported by environment)
194
*/
195
ClusterControllable controller
196
```
197
198
**Example Method Signatures:**
199
200
```java
201
// Sink test method
202
@TestTemplate
203
public void testBasicSink(
204
TestEnvironment testEnv,
205
DataStreamSinkExternalContext<String> externalContext,
206
CheckpointingMode semantic
207
) throws Exception {
208
// Test implementation
209
}
210
211
// Source test method with failure testing
212
@TestTemplate
213
public void testTaskManagerFailure(
214
TestEnvironment testEnv,
215
DataStreamSourceExternalContext<String> externalContext,
216
ClusterControllable controller,
217
CheckpointingMode semantic
218
) throws Exception {
219
// Test implementation
220
}
221
222
// Custom test method
223
@TestTemplate
224
public void testCustomScenario(
225
TestEnvironment testEnv,
226
DataStreamSinkExternalContext<String> sinkContext,
227
DataStreamSourceExternalContext<String> sourceContext,
228
CheckpointingMode semantic
229
) throws Exception {
230
// Custom test with multiple contexts
231
}
232
```
233
234
## Lifecycle Management
235
236
### PER-CLASS Resources
237
238
Resources with PER-CLASS lifecycle are shared across all test methods in the class.
239
240
```java
241
@TestEnv
242
MiniClusterTestEnvironment testEnv = new MiniClusterTestEnvironment();
243
244
// Lifecycle:
245
// 1. Created when test class is instantiated
246
// 2. Started before first test method (@BeforeAll phase)
247
// 3. Shared by all test methods in the class
248
// 4. Stopped after last test method (@AfterAll phase)
249
```
250
251
**Benefits:**
252
- **Performance**: Avoids expensive cluster startup/teardown per test
253
- **Resource Efficiency**: Reduces memory and CPU usage
254
- **Test Speed**: Faster test execution
255
256
### PER-CASE Resources
257
258
Resources with PER-CASE lifecycle are created fresh for each test case.
259
260
```java
261
@TestContext
262
ExternalContextFactory<MySinkExternalContext> contextFactory =
263
testName -> new MySinkExternalContext(testName);
264
265
// Lifecycle:
266
// 1. Factory created when test class is instantiated
267
// 2. New context instance created before each test case
268
// 3. Context used during test execution
269
// 4. Context closed after test case completion
270
```
271
272
**Benefits:**
273
- **Test Isolation**: Each test gets fresh external resources
274
- **Resource Cleanup**: Automatic cleanup prevents resource leaks
275
- **Parallel Safety**: Tests can run in parallel safely
276
277
### Lifecycle Sequence
278
279
```java
280
// Class initialization
281
TestClass instance = new TestClass();
282
283
// Before all tests
284
@BeforeAll
285
testEnv.startUp(); // Start test environment
286
287
// For each test method
288
for (TestMethod method : testMethods) {
289
// For each parameter combination
290
for (ParameterCombination params : combinations) {
291
292
// Before each test case
293
ExternalContext context = contextFactory.createExternalContext(testName);
294
295
try {
296
// Execute test
297
method.invoke(testEnv, context, semantic);
298
} finally {
299
// After each test case
300
context.close(); // Cleanup external resources
301
}
302
}
303
}
304
305
// After all tests
306
@AfterAll
307
testEnv.tearDown(); // Stop test environment
308
```
309
310
## Test Parameterization
311
312
### Automatic Parameter Generation
313
314
The framework automatically generates test parameter combinations:
315
316
```java
317
// Configuration
318
@TestContext
319
ExternalContextFactory<Context1> context1Factory = ...;
320
321
@TestContext
322
ExternalContextFactory<Context2> context2Factory = ...;
323
324
@TestSemantics
325
List<CheckpointingMode> semantics = Arrays.asList(
326
CheckpointingMode.EXACTLY_ONCE,
327
CheckpointingMode.AT_LEAST_ONCE
328
);
329
330
// Generated combinations:
331
// 1. testMethod(testEnv, context1, EXACTLY_ONCE)
332
// 2. testMethod(testEnv, context1, AT_LEAST_ONCE)
333
// 3. testMethod(testEnv, context2, EXACTLY_ONCE)
334
// 4. testMethod(testEnv, context2, AT_LEAST_ONCE)
335
```
336
337
### Display Names
338
339
Test cases get descriptive display names based on parameters:
340
341
```java
342
// Generated display names:
343
// ✓ testBasicSink[Context1, EXACTLY_ONCE]
344
// ✓ testBasicSink[Context1, AT_LEAST_ONCE]
345
// ✓ testBasicSink[Context2, EXACTLY_ONCE]
346
// ✓ testBasicSink[Context2, AT_LEAST_ONCE]
347
```
348
349
### Custom Parameterization
350
351
Override default parameterization for specific test methods:
352
353
```java
354
@TestTemplate
355
@ParameterizedTest
356
@EnumSource(CheckpointingMode.class)
357
public void testCustomParameterization(
358
TestEnvironment testEnv,
359
DataStreamSinkExternalContext<String> externalContext,
360
CheckpointingMode semantic
361
) throws Exception {
362
// Custom parameterization using JUnit 5 @ParameterizedTest
363
}
364
```
365
366
## Advanced Configuration
367
368
### Multiple External Systems
369
370
Test with multiple external systems simultaneously:
371
372
```java
373
@TestContext
374
ExternalContextFactory<DatabaseExternalContext> dbContextFactory =
375
testName -> new DatabaseExternalContext(testName);
376
377
@TestContext
378
ExternalContextFactory<MessageQueueExternalContext> mqContextFactory =
379
testName -> new MessageQueueExternalContext(testName);
380
381
@TestTemplate
382
public void testDatabaseToMessageQueue(
383
TestEnvironment testEnv,
384
DatabaseExternalContext dbContext,
385
MessageQueueExternalContext mqContext,
386
CheckpointingMode semantic
387
) throws Exception {
388
// Test data flow from database to message queue
389
}
390
```
391
392
### Conditional Test Execution
393
394
Skip tests based on environment or configuration:
395
396
```java
397
@TestTemplate
398
public void testContainerizedEnvironment(
399
TestEnvironment testEnv,
400
DataStreamSinkExternalContext<String> externalContext,
401
CheckpointingMode semantic
402
) throws Exception {
403
404
assumeTrue(testEnv instanceof FlinkContainerTestEnvironment,
405
"Test requires containerized environment");
406
407
// Test implementation
408
}
409
410
@TestTemplate
411
public void testExactlyOnceOnly(
412
TestEnvironment testEnv,
413
DataStreamSinkExternalContext<String> externalContext,
414
CheckpointingMode semantic
415
) throws Exception {
416
417
assumeTrue(semantic == CheckpointingMode.EXACTLY_ONCE,
418
"Test only valid for exactly-once semantic");
419
420
// Test implementation
421
}
422
```
423
424
### Error Handling Configuration
425
426
Configure error handling behavior:
427
428
```java
429
@ExtendWith(ConnectorTestingExtension.class)
430
@TestMethodOrder(OrderAnnotation.class)
431
public class MyConnectorTestSuite extends SinkTestSuiteBase<String> {
432
433
@TestEnv
434
MiniClusterTestEnvironment testEnv = new MiniClusterTestEnvironment();
435
436
@TestContext
437
ExternalContextFactory<MySinkExternalContext> contextFactory = testName -> {
438
try {
439
return new MySinkExternalContext(testName);
440
} catch (Exception e) {
441
// Convert to TestAbortedException to skip test instead of failing
442
throw new TestAbortedException("External system not available", e);
443
}
444
};
445
446
@Order(1)
447
@TestTemplate
448
public void testPrerequisites(TestEnvironment testEnv) {
449
// Verify prerequisites before running main tests
450
assumeTrue(checkExternalSystemAvailability(),
451
"External system not available");
452
}
453
}
454
```
455
456
## Integration with IDEs
457
458
### IntelliJ IDEA
459
460
- **Test Discovery**: Automatically discovers `@TestTemplate` methods
461
- **Parameter Display**: Shows parameter combinations in test tree
462
- **Debug Support**: Full debugging support with parameter inspection
463
- **Test Filtering**: Filter tests by parameter values
464
465
### Eclipse
466
467
- **JUnit 5 Support**: Requires JUnit 5 plugin for full support
468
- **Test Execution**: Run individual parameter combinations
469
- **Progress Reporting**: Shows progress across parameter combinations
470
471
### Maven/Gradle
472
473
```xml
474
<!-- Maven Surefire configuration -->
475
<plugin>
476
<groupId>org.apache.maven.plugins</groupId>
477
<artifactId>maven-surefire-plugin</artifactId>
478
<version>3.0.0-M9</version>
479
<configuration>
480
<includes>
481
<include>**/*TestSuite.java</include>
482
</includes>
483
<!-- Enable parallel execution -->
484
<parallel>methods</parallel>
485
<threadCount>4</threadCount>
486
</configuration>
487
</plugin>
488
```
489
490
```gradle
491
// Gradle test configuration
492
test {
493
useJUnitPlatform()
494
495
// Enable parallel execution
496
maxParallelForks = 4
497
498
// Configure test logging
499
testLogging {
500
events "passed", "skipped", "failed"
501
showStandardStreams = true
502
}
503
}
504
```