0
# KotlinTest Runner JUnit5
1
2
KotlinTest Runner JUnit5 is a JUnit Platform TestEngine implementation that integrates the KotlinTest testing framework with JUnit 5 ecosystem. It enables KotlinTest specifications to be discovered and executed by JUnit Platform launchers, allowing KotlinTest's expressive testing styles to work seamlessly with JUnit 5 tooling including IDEs, build tools like Gradle and Maven, and CI/CD systems.
3
4
## Package Information
5
6
- **Package Name**: kotlintest-runner-junit5
7
- **Package Type**: maven
8
- **Language**: Kotlin
9
- **Group ID**: io.kotlintest
10
- **Artifact ID**: kotlintest-runner-junit5
11
- **Installation**: Add to build.gradle: `testImplementation 'io.kotlintest:kotlintest-runner-junit5:3.4.2'`
12
13
## Core Imports
14
15
```kotlin
16
import io.kotlintest.runner.junit5.KotlinTestEngine
17
import io.kotlintest.specs.*
18
```
19
20
For test specifications, extend from the spec classes:
21
22
```kotlin
23
import io.kotlintest.specs.StringSpec
24
import io.kotlintest.specs.FunSpec
25
import io.kotlintest.specs.BehaviorSpec
26
// ... other spec types
27
```
28
29
## Basic Usage
30
31
```kotlin
32
// Example test using StringSpec with JUnit 5 integration
33
import io.kotlintest.specs.StringSpec
34
import io.kotlintest.shouldBe
35
36
class CalculatorTest : StringSpec({
37
"addition should work correctly" {
38
val result = 2 + 2
39
result shouldBe 4
40
}
41
42
"multiplication should work correctly" {
43
val result = 3 * 4
44
result shouldBe 12
45
}
46
})
47
```
48
49
The engine is automatically discovered by JUnit Platform through service loading, so no explicit configuration is needed beyond adding the dependency.
50
51
## Architecture
52
53
The integration works through several key components:
54
55
- **TestEngine Implementation**: `KotlinTestEngine` implements JUnit Platform's TestEngine interface
56
- **Test Discovery**: Converts JUnit discovery requests to KotlinTest's internal format
57
- **Execution Bridging**: Translates KotlinTest's test execution model to JUnit Platform's execution lifecycle
58
- **IDE Integration**: IntelliJ-compatible spec classes for better development experience
59
- **Thread Safety**: Synchronized execution listeners to handle concurrent test execution
60
61
## Capabilities
62
63
### Test Engine Implementation
64
65
Core JUnit Platform TestEngine that discovers and executes KotlinTest specifications.
66
67
```kotlin { .api }
68
class KotlinTestEngine : TestEngine {
69
companion object {
70
const val EngineId = "kotlintest"
71
}
72
73
override fun getId(): String
74
override fun discover(
75
request: EngineDiscoveryRequest,
76
uniqueId: UniqueId
77
): KotlinTestEngineDescriptor
78
override fun execute(request: ExecutionRequest)
79
80
class KotlinTestEngineDescriptor(
81
id: UniqueId,
82
val classes: List<KClass<out Spec>>
83
) : EngineDescriptor {
84
override fun mayRegisterTests(): Boolean
85
}
86
}
87
```
88
89
### Test Execution Listener
90
91
JUnit Platform execution listener that bridges KotlinTest's execution events to JUnit Platform's reporting model.
92
93
```kotlin { .api }
94
class JUnitTestRunnerListener(
95
private val listener: EngineExecutionListener,
96
val root: EngineDescriptor
97
) : TestEngineListener {
98
99
data class ResultState(val testCase: TestCase, val result: TestResult)
100
101
override fun engineStarted(classes: List<KClass<out Spec>>)
102
override fun engineFinished(t: Throwable?)
103
override fun beforeSpecClass(klass: KClass<out Spec>)
104
override fun afterSpecClass(klass: KClass<out Spec>, t: Throwable?)
105
override fun enterTestCase(testCase: TestCase)
106
override fun invokingTestCase(testCase: TestCase, k: Int)
107
override fun exitTestCase(testCase: TestCase, result: TestResult)
108
override fun specInitialisationFailed(klass: KClass<out Spec>, t: Throwable)
109
}
110
```
111
112
### Thread-Safe Execution Listener
113
114
Synchronized wrapper around EngineExecutionListener to handle concurrent test execution safely.
115
116
```kotlin { .api }
117
class SynchronizedEngineExecutionListener(
118
val listener: EngineExecutionListener
119
) : EngineExecutionListener {
120
121
override fun executionFinished(
122
testDescriptor: TestDescriptor?,
123
testExecutionResult: TestExecutionResult?
124
)
125
override fun reportingEntryPublished(
126
testDescriptor: TestDescriptor?,
127
entry: ReportEntry?
128
)
129
override fun executionSkipped(
130
testDescriptor: TestDescriptor?,
131
reason: String?
132
)
133
override fun executionStarted(testDescriptor: TestDescriptor?)
134
override fun dynamicTestRegistered(testDescriptor: TestDescriptor?)
135
}
136
```
137
138
### Discovery Request Conversion
139
140
Utility function that converts JUnit Platform discovery requests to KotlinTest's internal discovery format.
141
142
```kotlin { .api }
143
/**
144
* Returns a KotlinTest [DiscoveryRequest] built from the selectors and filters present
145
* in the JUnit [EngineDiscoveryRequest].
146
*
147
* Supported selectors are:
148
* - [ClassSelector] - used to specify a single class by fully qualified name
149
* - [DirectorySelector] - classes are scanned in the given directory
150
* - [UriSelector] - classes are scanned from the given uri
151
* - [PackageSelector] - classes are scanned on the default classpath for the given package name
152
*
153
* Support filters are:
154
* - [ClassNameFilter] - filters out specs based on a classname
155
* - [PackageNameFilter] - filters out specs based on package names
156
*
157
* Unsupported selectors are:
158
* - [MethodSelector] - not supported because kotlintest does not define tests as methods/functions
159
*/
160
internal fun discoveryRequest(request: EngineDiscoveryRequest): DiscoveryRequest
161
```
162
163
### IntelliJ IDE Integration Specs
164
165
Abstract spec classes that provide better IntelliJ IDEA integration through marker interface and annotations.
166
167
```kotlin { .api }
168
interface IntelliMarker {
169
@EnabledIfSystemProperty(named = "wibble", matches = "wobble")
170
@TestFactory
171
fun primer() {
172
}
173
}
174
175
abstract class AnnotationSpec(
176
body: AbstractAnnotationSpec.() -> Unit = {}
177
) : AbstractAnnotationSpec(body), IntelliMarker
178
179
abstract class BehaviorSpec(
180
body: AbstractBehaviorSpec.() -> Unit = {}
181
) : AbstractBehaviorSpec(body), IntelliMarker
182
183
abstract class DescribeSpec(
184
body: AbstractDescribeSpec.() -> Unit = {}
185
) : AbstractDescribeSpec(body), IntelliMarker
186
187
abstract class ExpectSpec(
188
body: AbstractExpectSpec.() -> Unit = {}
189
) : AbstractExpectSpec(body), IntelliMarker
190
191
abstract class FeatureSpec(
192
body: AbstractFeatureSpec.() -> Unit = {}
193
) : AbstractFeatureSpec(body), IntelliMarker
194
195
abstract class FreeSpec(
196
body: AbstractFreeSpec.() -> Unit = {}
197
) : AbstractFreeSpec(body), IntelliMarker
198
199
abstract class FunSpec(
200
body: AbstractFunSpec.() -> Unit = {}
201
) : AbstractFunSpec(body), IntelliMarker
202
203
abstract class ShouldSpec(
204
body: AbstractShouldSpec.() -> Unit = {}
205
) : AbstractShouldSpec(body), IntelliMarker {
206
infix fun String.should(matcher: Matcher<String>): Unit
207
}
208
209
abstract class StringSpec(
210
body: AbstractStringSpec.() -> Unit = {}
211
) : AbstractStringSpec(body), IntelliMarker
212
213
abstract class WordSpec(
214
body: AbstractWordSpec.() -> Unit = {}
215
) : AbstractWordSpec(body), IntelliMarker {
216
infix fun String?.should(matcher: Matcher<String?>): Unit
217
}
218
```
219
220
### Debug Utilities
221
222
Extension functions for debugging JUnit Platform discovery requests.
223
224
```kotlin { .api }
225
fun EngineDiscoveryRequest.string(): String
226
fun LauncherDiscoveryRequest.string(): String
227
```
228
229
### UniqueId Extensions
230
231
Extension function for creating spec-specific unique IDs in the JUnit Platform descriptor hierarchy.
232
233
```kotlin { .api }
234
fun UniqueId.appendSpec(description: Description): UniqueId
235
```
236
237
## Types
238
239
```kotlin { .api }
240
// From KotlinTest framework (imported dependencies)
241
interface Spec
242
interface TestEngineListener
243
interface TestCase
244
interface TestResult
245
interface TestStatus
246
interface Description
247
class Matcher<T>
248
249
// From JUnit Platform (imported dependencies)
250
interface TestEngine
251
interface EngineDiscoveryRequest
252
interface ExecutionRequest
253
interface TestDescriptor
254
interface EngineExecutionListener
255
interface TestExecutionResult
256
interface ReportEntry
257
class UniqueId
258
class EngineDescriptor
259
260
```
261
262
## Service Registration
263
264
The engine is automatically registered with JUnit Platform through Java's ServiceLoader mechanism:
265
266
- **Service File**: `META-INF/services/org.junit.platform.engine.TestEngine`
267
- **Implementation**: `io.kotlintest.runner.junit5.KotlinTestEngine`
268
269
This allows JUnit Platform to automatically discover and use the KotlinTest engine without explicit configuration.
270
271
## Error Handling
272
273
The engine handles various error scenarios:
274
275
- **Spec Initialization Failures**: Reported as test failures in JUnit Platform
276
- **Test Execution Failures**: Converted to JUnit Platform's TestExecutionResult format
277
- **Discovery Errors**: Logged and result in empty test descriptor sets
278
- **Thread Safety**: All listener notifications are synchronized to prevent race conditions
279
280
## Integration Notes
281
282
- **Gradle Integration**: Works with Gradle's JUnit Platform support
283
- **Maven Integration**: Compatible with Maven Surefire plugin's JUnit Platform support
284
- **IDE Support**: IntelliJ IDEA can discover and run KotlinTest specifications
285
- **CI/CD**: Works with any CI/CD system that supports JUnit Platform
286
- **Filtering**: Supports JUnit Platform's test filtering mechanisms (packages, classes, etc.)
287
- **Parallel Execution**: Respects KotlinTest's parallelism configuration