0
# JUnit Integration
1
2
JUnit 4 and JUnit 5 extensions that automatically set up OpenTelemetry SDK for testing with in-memory exporters and convenient access to collected telemetry data. These extensions handle the lifecycle of OpenTelemetry configuration and provide easy access to captured spans, metrics, and logs.
3
4
## Capabilities
5
6
### JUnit 5 Extension
7
8
JUnit 5 extension that configures OpenTelemetry SDK with in-memory exporters and provides convenient access to collected telemetry data.
9
10
```java { .api }
11
class OpenTelemetryExtension implements BeforeEachCallback, BeforeAllCallback, AfterAllCallback {
12
// Factory method
13
static OpenTelemetryExtension create();
14
15
// OpenTelemetry access
16
OpenTelemetry getOpenTelemetry();
17
18
// Collected data access
19
List<SpanData> getSpans();
20
List<MetricData> getMetrics();
21
List<LogRecordData> getLogRecords();
22
23
// Assertion helper
24
TracesAssert assertTraces();
25
26
// Data management
27
void clearSpans();
28
void clearMetrics();
29
void clearLogRecords();
30
}
31
```
32
33
Usage examples:
34
35
```java
36
import io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension;
37
import org.junit.jupiter.api.Test;
38
import org.junit.jupiter.api.extension.RegisterExtension;
39
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.*;
40
41
class MyServiceTest {
42
43
@RegisterExtension
44
static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create();
45
46
@Test
47
void testServiceOperation() {
48
// Get the configured OpenTelemetry instance
49
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
50
51
// Initialize your service with the test OpenTelemetry
52
MyService service = new MyService(openTelemetry);
53
54
// Execute the operation that should create telemetry
55
service.performOperation("test-input");
56
57
// Validate collected spans
58
assertThat(otelTesting.getSpans())
59
.hasSize(2)
60
.satisfiesExactly(
61
span -> assertThat(span)
62
.hasName("service.operation")
63
.hasAttribute(AttributeKey.stringKey("input"), "test-input"),
64
span -> assertThat(span)
65
.hasName("database.query")
66
.hasKind(SpanKind.CLIENT)
67
);
68
69
// Validate collected metrics
70
assertThat(otelTesting.getMetrics())
71
.hasSize(1)
72
.first()
73
.hasName("operation.duration")
74
.hasDoubleGaugeSatisfying(gauge ->
75
gauge.hasPointsSatisfying(point ->
76
point.hasValue(greaterThan(0.0))
77
)
78
);
79
80
// Validate collected logs
81
assertThat(otelTesting.getLogRecords())
82
.hasSize(1)
83
.first()
84
.hasBody("Operation completed successfully")
85
.hasSeverity(Severity.INFO);
86
}
87
88
@Test
89
void testWithTraceAssertions() {
90
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
91
MyService service = new MyService(openTelemetry);
92
93
service.performNestedOperations();
94
95
// Use the built-in trace assertions
96
otelTesting.assertTraces()
97
.hasTracesSatisfyingExactly(
98
trace -> trace.hasSpansSatisfyingExactly(
99
span -> assertThat(span).hasName("parent.operation"),
100
span -> assertThat(span).hasName("child.operation.1"),
101
span -> assertThat(span).hasName("child.operation.2")
102
)
103
);
104
}
105
106
@Test
107
void testDataClearing() {
108
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
109
MyService service = new MyService(openTelemetry);
110
111
// First operation
112
service.performOperation("first");
113
assertThat(otelTesting.getSpans()).hasSize(1);
114
115
// Clear data and perform second operation
116
otelTesting.clearSpans();
117
service.performOperation("second");
118
assertThat(otelTesting.getSpans()).hasSize(1);
119
assertThat(otelTesting.getSpans().get(0))
120
.hasAttribute(AttributeKey.stringKey("input"), "second");
121
}
122
}
123
```
124
125
### JUnit 4 Rule
126
127
JUnit 4 rule that provides the same functionality as the JUnit 5 extension for projects using JUnit 4.
128
129
```java { .api }
130
class OpenTelemetryRule extends ExternalResource {
131
// Factory method
132
static OpenTelemetryRule create();
133
134
// OpenTelemetry access (identical to JUnit 5 extension)
135
OpenTelemetry getOpenTelemetry();
136
137
// Collected data access
138
List<SpanData> getSpans();
139
List<MetricData> getMetrics();
140
List<LogRecordData> getLogRecords();
141
142
// Data management
143
void clearSpans();
144
void clearMetrics();
145
void clearLogRecords();
146
}
147
```
148
149
Usage examples:
150
151
```java
152
import io.opentelemetry.sdk.testing.junit4.OpenTelemetryRule;
153
import org.junit.Rule;
154
import org.junit.Test;
155
import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.*;
156
157
public class MyServiceTest {
158
159
@Rule
160
public final OpenTelemetryRule otelTesting = OpenTelemetryRule.create();
161
162
@Test
163
public void testServiceOperation() {
164
// Get the configured OpenTelemetry instance
165
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
166
167
// Initialize your service with the test OpenTelemetry
168
MyService service = new MyService(openTelemetry);
169
170
// Execute the operation
171
service.performOperation("test-input");
172
173
// Validate collected data
174
assertThat(otelTesting.getSpans())
175
.hasSize(1)
176
.first()
177
.hasName("service.operation")
178
.hasAttribute(AttributeKey.stringKey("input"), "test-input");
179
}
180
181
@Test
182
public void testMultipleOperations() {
183
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
184
MyService service = new MyService(openTelemetry);
185
186
// Perform multiple operations
187
service.performOperation("first");
188
service.performOperation("second");
189
190
// Validate all collected spans
191
assertThat(otelTesting.getSpans())
192
.hasSize(2)
193
.extracting(SpanData::getName)
194
.containsExactly("service.operation", "service.operation");
195
196
// Validate attributes of specific spans
197
assertThat(otelTesting.getSpans().get(0))
198
.hasAttribute(AttributeKey.stringKey("input"), "first");
199
assertThat(otelTesting.getSpans().get(1))
200
.hasAttribute(AttributeKey.stringKey("input"), "second");
201
}
202
}
203
```
204
205
## Configuration and Lifecycle
206
207
### Automatic Configuration
208
209
Both the JUnit 5 extension and JUnit 4 rule automatically configure:
210
211
- **SdkTracerProvider** with InMemorySpanExporter
212
- **SdkMeterProvider** with InMemoryMetricReader
213
- **SdkLoggerProvider** with InMemoryLogRecordExporter
214
- **Resource** with basic service information
215
- **Batch processors** for efficient data collection
216
217
### Lifecycle Management
218
219
The extensions handle the complete lifecycle:
220
221
1. **Setup** (before all/each test): Initialize OpenTelemetry SDK with testing configuration
222
2. **Execution**: Provide configured OpenTelemetry instance to tests
223
3. **Cleanup** (after all tests): Shutdown SDK components properly
224
4. **Data clearing**: Automatic clearing between tests (JUnit 5) or manual clearing (both)
225
226
### Data Collection Behavior
227
228
```java
229
// Data collection happens automatically during test execution
230
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
231
232
// Create telemetry in your code
233
Tracer tracer = openTelemetry.getTracer("test");
234
Span span = tracer.spanBuilder("operation").startSpan();
235
span.end();
236
237
// Data is immediately available for assertions
238
List<SpanData> spans = otelTesting.getSpans(); // Contains the created span
239
```
240
241
## Advanced Usage Patterns
242
243
### Custom Service Configuration
244
245
```java
246
@Test
247
void testWithCustomConfiguration() {
248
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
249
250
// Configure your service with additional resources or instrumentation
251
MyService service = MyService.builder()
252
.withOpenTelemetry(openTelemetry)
253
.withResource(Resource.getDefault().merge(
254
Resource.builder()
255
.put(ResourceAttributes.SERVICE_NAME, "test-service")
256
.put(ResourceAttributes.SERVICE_VERSION, "1.0.0")
257
.build()))
258
.build();
259
260
service.performOperation();
261
262
// Validate resource attributes
263
assertThat(otelTesting.getSpans())
264
.first()
265
.hasResourceSatisfying(resource ->
266
assertThat(resource)
267
.hasAttribute(ResourceAttributes.SERVICE_NAME, "test-service")
268
.hasAttribute(ResourceAttributes.SERVICE_VERSION, "1.0.0")
269
);
270
}
271
```
272
273
### Testing Error Scenarios
274
275
```java
276
@Test
277
void testErrorHandling() {
278
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
279
MyService service = new MyService(openTelemetry);
280
281
// Trigger an error condition
282
assertThrows(ServiceException.class, () ->
283
service.performOperation("invalid-input"));
284
285
// Validate error span
286
assertThat(otelTesting.getSpans())
287
.first()
288
.hasName("service.operation")
289
.hasStatusSatisfying(status ->
290
status.hasCode(StatusCode.ERROR)
291
.hasDescription("Invalid input provided")
292
)
293
.hasException(ServiceException.class);
294
295
// Validate error logs
296
assertThat(otelTesting.getLogRecords())
297
.first()
298
.hasSeverity(Severity.ERROR)
299
.hasBody(containsString("Failed to process input"));
300
}
301
```
302
303
### Parameterized Tests
304
305
```java
306
@ParameterizedTest
307
@ValueSource(strings = {"input1", "input2", "input3"})
308
void testParameterizedOperations(String input) {
309
OpenTelemetry openTelemetry = otelTesting.getOpenTelemetry();
310
MyService service = new MyService(openTelemetry);
311
312
service.performOperation(input);
313
314
assertThat(otelTesting.getSpans())
315
.hasSize(1)
316
.first()
317
.hasAttribute(AttributeKey.stringKey("input"), input);
318
319
// Clear data for next parameterized test
320
otelTesting.clearSpans();
321
}
322
```
323
324
## Types
325
326
```java { .api }
327
// JUnit 5 callback interfaces
328
interface BeforeEachCallback {
329
void beforeEach(ExtensionContext context) throws Exception;
330
}
331
332
interface BeforeAllCallback {
333
void beforeAll(ExtensionContext context) throws Exception;
334
}
335
336
interface AfterAllCallback {
337
void afterAll(ExtensionContext context) throws Exception;
338
}
339
340
// JUnit 4 rule base class
341
abstract class ExternalResource implements TestRule {
342
protected void before() throws Throwable;
343
protected void after();
344
}
345
346
// OpenTelemetry SDK components configured by extensions
347
interface OpenTelemetry {
348
TracerProvider getTracerProvider();
349
MeterProvider getMeterProvider();
350
LoggerProvider getLoggerProvider();
351
}
352
353
// Data types returned by extensions
354
interface SpanData { /* Completed span data */ }
355
interface MetricData { /* Metric measurement data */ }
356
interface LogRecordData { /* Log record data */ }
357
358
// Assertion helper type
359
class TracesAssert extends AbstractAssert<TracesAssert, Collection<List<SpanData>>> {
360
TracesAssert hasTracesSatisfyingExactly(Consumer<TraceAssert>... assertions);
361
}
362
```