JUnit Jupiter extension that enables automatic lifecycle management of Docker containers in JUnit 5 tests
npx @tessl/cli install tessl/maven-org-testcontainers--junit-jupiter@1.21.00
# Testcontainers JUnit Jupiter
1
2
A JUnit Jupiter extension that enables automatic lifecycle management of Docker containers in JUnit 5 tests. The extension provides annotations to seamlessly integrate container-based testing into the JUnit Jupiter framework, supporting both static containers (shared between test methods) and instance containers (started/stopped per test method).
3
4
## Package Information
5
6
- **Package Name**: org.testcontainers:junit-jupiter
7
- **Package Type**: Maven
8
- **Language**: Java
9
- **Installation**:
10
- **Maven**:
11
```xml
12
<dependency>
13
<groupId>org.testcontainers</groupId>
14
<artifactId>junit-jupiter</artifactId>
15
<version>1.21.3</version>
16
<scope>test</scope>
17
</dependency>
18
```
19
- **Gradle**:
20
```gradle
21
testImplementation 'org.testcontainers:junit-jupiter:1.21.3'
22
```
23
24
## Core Imports
25
26
```java
27
import org.testcontainers.junit.jupiter.Testcontainers;
28
import org.testcontainers.junit.jupiter.Container;
29
import org.testcontainers.junit.jupiter.EnabledIfDockerAvailable;
30
```
31
32
## Basic Usage
33
34
```java
35
import org.testcontainers.containers.PostgreSQLContainer;
36
import org.testcontainers.containers.MySQLContainer;
37
import org.testcontainers.junit.jupiter.Container;
38
import org.testcontainers.junit.jupiter.Testcontainers;
39
import org.junit.jupiter.api.Test;
40
import static org.junit.jupiter.api.Assertions.assertTrue;
41
42
@Testcontainers
43
class MyTestcontainersTests {
44
45
// Shared between test methods - started once, stopped after all tests
46
@Container
47
private static final MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");
48
49
// Started before and stopped after each test method
50
@Container
51
private PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13")
52
.withDatabaseName("testdb")
53
.withUsername("test")
54
.withPassword("test");
55
56
@Test
57
void testContainersAreRunning() {
58
assertTrue(mysql.isRunning());
59
assertTrue(postgres.isRunning());
60
}
61
}
62
```
63
64
## Architecture
65
66
The JUnit Jupiter extension integrates with JUnit 5's extension model through several key components:
67
68
- **Annotation Processing**: Scans test classes for `@Container` annotated fields and manages their lifecycle
69
- **Extension Hooks**: Implements JUnit's `BeforeAllCallback`, `AfterAllCallback`, `BeforeEachCallback`, `AfterEachCallback`, and `ExecutionCondition` for precise container lifecycle control
70
- **Conditional Execution**: Provides execution conditions to skip or disable tests when Docker is unavailable
71
- **Parallel Support**: Enables parallel container startup for improved test performance when configured
72
- **Lifecycle Integration**: Connects with `TestLifecycleAware` containers to provide test context information
73
74
## Capabilities
75
76
### Container Lifecycle Management
77
78
Automatically manages Docker container startup and shutdown through the `@Testcontainers` annotation and `@Container` field annotation.
79
80
```java { .api }
81
@Target(ElementType.TYPE)
82
@Retention(RetentionPolicy.RUNTIME)
83
@ExtendWith(TestcontainersExtension.class)
84
@Inherited
85
public @interface Testcontainers {
86
/**
87
* Whether tests should be disabled (rather than failing) when Docker is not available.
88
* @return if the tests should be disabled when Docker is not available
89
*/
90
boolean disabledWithoutDocker() default false;
91
92
/**
93
* Whether containers should start in parallel.
94
* @return if the containers should start in parallel
95
*/
96
boolean parallel() default false;
97
}
98
99
@Target({ ElementType.FIELD, ElementType.ANNOTATION_TYPE })
100
@Retention(RetentionPolicy.RUNTIME)
101
public @interface Container {
102
}
103
```
104
105
**Container Lifecycle Rules:**
106
- **Static fields** with `@Container`: Shared between all test methods in the class. Started once before any test method executes, stopped after the last test method completes.
107
- **Instance fields** with `@Container`: Restarted for each individual test method. Started before each test method, stopped after each test method.
108
- **Container Requirements**: Fields annotated with `@Container` must implement `org.testcontainers.lifecycle.Startable` interface.
109
110
**Usage Examples:**
111
112
```java
113
@Testcontainers
114
class ContainerLifecycleExample {
115
116
// Shared container - expensive to start, reused across tests
117
@Container
118
static final PostgreSQLContainer<?> sharedPostgres =
119
new PostgreSQLContainer<>("postgres:13");
120
121
// Per-test container - fresh instance for each test
122
@Container
123
RedisContainer redis = new RedisContainer("redis:6-alpine");
124
125
@Test
126
void testWithFreshRedis() {
127
// redis container is started fresh for this test
128
String redisUrl = redis.getRedisURI();
129
// ... test logic
130
}
131
132
@Test
133
void testWithSharedPostgres() {
134
// sharedPostgres container was started once and is reused
135
String jdbcUrl = sharedPostgres.getJdbcUrl();
136
// ... test logic
137
}
138
}
139
```
140
141
### Conditional Test Execution
142
143
Provides Docker availability detection and conditional test execution capabilities.
144
145
```java { .api }
146
@Target({ ElementType.TYPE, ElementType.METHOD })
147
@Retention(RetentionPolicy.RUNTIME)
148
@Documented
149
@ExtendWith(EnabledIfDockerAvailableCondition.class)
150
public @interface EnabledIfDockerAvailable {
151
}
152
```
153
154
**Docker Availability Options:**
155
156
1. **Fail when Docker unavailable** (default behavior):
157
```java
158
@Testcontainers
159
class MyTests {
160
// Tests will fail if Docker is not available
161
}
162
```
163
164
2. **Disable tests when Docker unavailable**:
165
```java
166
@Testcontainers(disabledWithoutDocker = true)
167
class MyTests {
168
// Tests will be skipped if Docker is not available
169
}
170
```
171
172
3. **Method-level Docker requirement**:
173
```java
174
class MyTests {
175
176
@Test
177
@EnabledIfDockerAvailable
178
void testRequiringDocker() {
179
// This test only runs if Docker is available
180
}
181
182
@Test
183
void testNotRequiringDocker() {
184
// This test always runs
185
}
186
}
187
```
188
189
### Extension Integration
190
191
The extension integrates with JUnit Jupiter's lifecycle and provides access to the underlying extension functionality.
192
193
```java { .api }
194
public class TestcontainersExtension
195
implements BeforeEachCallback, BeforeAllCallback, AfterEachCallback, AfterAllCallback, ExecutionCondition {
196
197
/**
198
* Check if Docker is available on the system
199
* @return true if Docker client can be created and accessed
200
*/
201
public boolean isDockerAvailable();
202
}
203
```
204
205
**Parallel Container Startup:**
206
207
```java
208
@Testcontainers(parallel = true)
209
class ParallelStartupExample {
210
211
@Container
212
static final PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:13");
213
214
@Container
215
static final MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");
216
217
@Container
218
static final RedisContainer redis = new RedisContainer("redis:6-alpine");
219
220
// All three containers will start in parallel, reducing total startup time
221
}
222
```
223
224
**Test Lifecycle Integration:**
225
226
For containers implementing `org.testcontainers.lifecycle.TestLifecycleAware`, the extension provides test context:
227
228
```java
229
// Container receives test lifecycle callbacks
230
public class MyCustomContainer extends GenericContainer<MyCustomContainer>
231
implements TestLifecycleAware {
232
233
@Override
234
public void beforeTest(TestDescription description) {
235
// Called before each test method
236
// description provides test ID and filesystem-friendly name
237
}
238
239
@Override
240
public void afterTest(TestDescription description, Optional<Throwable> throwable) {
241
// Called after each test method
242
// throwable contains test failure information if test failed
243
}
244
}
245
```
246
247
## Error Handling
248
249
**Common Configuration Errors:**
250
251
- **`ExtensionConfigurationException`**: Thrown when `@Container` field does not implement `Startable` interface
252
- **`ExtensionConfigurationException`**: Thrown when `@Container` field is null (containers must be initialized)
253
- **`ExtensionConfigurationException`**: Thrown when `@Testcontainers` annotation is not found on class hierarchy
254
255
**Docker Availability Handling:**
256
257
- When `disabledWithoutDocker = false` (default): Tests fail with Docker connection errors if Docker is unavailable
258
- When `disabledWithoutDocker = true`: Tests are marked as disabled/skipped if Docker is unavailable
259
- `@EnabledIfDockerAvailable`: Individual tests/classes are skipped if Docker is unavailable
260
261
## Integration Requirements
262
263
**JUnit Jupiter**: Requires JUnit Jupiter 5.x (junit-jupiter-api dependency)
264
**Testcontainers Core**: Depends on org.testcontainers:testcontainers core library
265
**Docker**: Requires Docker daemon running and accessible to the test process
266
267
**Inheritance Support**: The `@Testcontainers` annotation is `@Inherited`, so subclasses automatically inherit the extension behavior from parent test classes.