0
# Framework Integration
1
2
Core interfaces and utilities for integrating with different testing frameworks across Kotlin multiplatform targets. This system provides a pluggable architecture that allows the same test code to work with JUnit, TestNG, JavaScript testing frameworks, and native testing environments.
3
4
## Capabilities
5
6
### Asserter Interface
7
8
The core interface that abstracts assertion logic and provides integration points for different testing frameworks.
9
10
```kotlin { .api }
11
/**
12
* Interface that abstracts the assertion logic and can be implemented by
13
* any testing framework to provide consistent assertion behavior across platforms.
14
*/
15
interface Asserter {
16
/**
17
* Marks a test as failed with the specified message.
18
* @param message The failure message, or null for default message
19
* @return Nothing (this function never returns normally)
20
*/
21
fun fail(message: String?): Nothing
22
23
/**
24
* Marks a test as failed with the specified message and cause.
25
* @param message The failure message, or null for default message
26
* @param cause The underlying cause of the failure, or null if none
27
* @return Nothing (this function never returns normally)
28
*/
29
fun fail(message: String?, cause: Throwable?): Nothing
30
31
/**
32
* Asserts that the value is true.
33
* @param lazyMessage Lazy-evaluated message provider for failure cases
34
* @param actual The boolean value to test
35
*/
36
fun assertTrue(lazyMessage: () -> String?, actual: Boolean)
37
38
/**
39
* Asserts that the value is true.
40
* @param message The failure message, or null for default
41
* @param actual The boolean value to test
42
*/
43
fun assertTrue(message: String?, actual: Boolean)
44
45
/**
46
* Asserts that the expected and actual values are equal.
47
* @param message The failure message, or null for default
48
* @param expected The expected value
49
* @param actual The actual value to compare
50
*/
51
fun assertEquals(message: String?, expected: Any?, actual: Any?)
52
53
/**
54
* Asserts that the illegal and actual values are not equal.
55
* @param message The failure message, or null for default
56
* @param illegal The value that should not match
57
* @param actual The actual value to compare
58
*/
59
fun assertNotEquals(message: String?, illegal: Any?, actual: Any?)
60
61
/**
62
* Asserts that the expected and actual references are the same instance.
63
* @param message The failure message, or null for default
64
* @param expected The expected object reference
65
* @param actual The actual object reference
66
*/
67
fun assertSame(message: String?, expected: Any?, actual: Any?)
68
69
/**
70
* Asserts that the illegal and actual references are not the same instance.
71
* @param message The failure message, or null for default
72
* @param illegal The reference that should not match
73
* @param actual The actual object reference
74
*/
75
fun assertNotSame(message: String?, illegal: Any?, actual: Any?)
76
77
/**
78
* Asserts that the actual value is null.
79
* @param message The failure message, or null for default
80
* @param actual The value to test for null
81
*/
82
fun assertNull(message: String?, actual: Any?)
83
84
/**
85
* Asserts that the actual value is not null.
86
* @param message The failure message, or null for default
87
* @param actual The value to test for non-null
88
*/
89
fun assertNotNull(message: String?, actual: Any?)
90
}
91
```
92
93
### AsserterContributor Interface
94
95
Interface for providing custom Asserter implementations in a pluggable way.
96
97
```kotlin { .api }
98
/**
99
* Interface for providing Asserter instances. Implementations can be registered
100
* to contribute custom assertion behavior for specific testing frameworks.
101
*/
102
interface AsserterContributor {
103
/**
104
* Provides an Asserter instance for the current testing context.
105
* @return An Asserter implementation, or null if this contributor
106
* cannot provide one for the current context
107
*/
108
fun contribute(): Asserter?
109
}
110
```
111
112
### Global Asserter Property
113
114
The global asserter property that holds the current assertion implementation.
115
116
```kotlin { .api }
117
/**
118
* The current Asserter instance used by all assertion functions.
119
* This can be replaced to integrate with different testing frameworks.
120
* Defaults to DefaultAsserter if no framework-specific asserter is available.
121
*/
122
var asserter: Asserter
123
```
124
125
**Usage Examples:**
126
127
```kotlin
128
import kotlin.test.*
129
130
@Test
131
fun testCustomAsserterIntegration() {
132
// Save the original asserter
133
val originalAsserter = asserter
134
135
try {
136
// Install a custom asserter for specialized behavior
137
asserter = CustomTestAsserter()
138
139
// All assertions now use the custom asserter
140
assertEquals("expected", "actual") // Uses CustomTestAsserter.assertEquals()
141
assertTrue(false) // Uses CustomTestAsserter.assertTrue()
142
143
} finally {
144
// Restore original asserter
145
asserter = originalAsserter
146
}
147
}
148
149
class CustomTestAsserter : Asserter {
150
override fun fail(message: String?): Nothing {
151
throw CustomAssertionError(message ?: "Assertion failed")
152
}
153
154
override fun fail(message: String?, cause: Throwable?): Nothing {
155
throw CustomAssertionError(message ?: "Assertion failed", cause)
156
}
157
158
override fun assertTrue(message: String?, actual: Boolean) {
159
if (!actual) {
160
fail(message ?: "Expected true but was false")
161
}
162
}
163
164
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
165
if (expected != actual) {
166
fail(message ?: "Expected <$expected> but was <$actual>")
167
}
168
}
169
170
// ... implement other methods
171
}
172
```
173
174
### DefaultAsserter Object
175
176
The default asserter implementation used when no framework-specific asserter is available.
177
178
```kotlin { .api }
179
/**
180
* Default Asserter implementation that provides basic assertion functionality
181
* without depending on any specific testing framework.
182
*/
183
object DefaultAsserter : Asserter {
184
/**
185
* Throws AssertionError with the specified message.
186
*/
187
override fun fail(message: String?): Nothing
188
189
/**
190
* Throws AssertionErrorWithCause with the specified message and cause.
191
*/
192
override fun fail(message: String?, cause: Throwable?): Nothing
193
}
194
```
195
196
## Platform-Specific Integration Examples
197
198
### JVM Integration (JUnit)
199
200
```kotlin
201
// Custom JUnit asserter implementation
202
class JUnitAsserter : Asserter {
203
override fun fail(message: String?): Nothing {
204
org.junit.Assert.fail(message)
205
throw AssertionError() // Never reached
206
}
207
208
override fun assertTrue(message: String?, actual: Boolean) {
209
org.junit.Assert.assertTrue(message, actual)
210
}
211
212
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
213
org.junit.Assert.assertEquals(message, expected, actual)
214
}
215
216
// ... other implementations delegate to JUnit
217
}
218
219
// Register the asserter
220
class JUnitAsserterContributor : AsserterContributor {
221
override fun contribute(): Asserter? {
222
return if (isJUnitAvailable()) JUnitAsserter() else null
223
}
224
225
private fun isJUnitAvailable(): Boolean {
226
return try {
227
Class.forName("org.junit.Assert")
228
true
229
} catch (e: ClassNotFoundException) {
230
false
231
}
232
}
233
}
234
```
235
236
### JavaScript Integration
237
238
```kotlin
239
// Custom JavaScript asserter for Node.js environments
240
class NodeJSAsserter : Asserter {
241
override fun fail(message: String?): Nothing {
242
js("throw new Error(message || 'Assertion failed')")
243
}
244
245
override fun assertTrue(message: String?, actual: Boolean) {
246
if (!actual) {
247
fail(message ?: "Expected true but was false")
248
}
249
}
250
251
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
252
js("""
253
const assert = require('assert');
254
assert.deepStrictEqual(actual, expected, message);
255
""")
256
}
257
258
// ... other implementations
259
}
260
```
261
262
### Native Integration
263
264
```kotlin
265
// Custom native asserter implementation
266
class NativeAsserter : Asserter {
267
override fun fail(message: String?): Nothing {
268
// Native-specific error reporting
269
platform.posix.fprintf(platform.posix.stderr, "ASSERTION FAILED: %s\n", message ?: "")
270
platform.posix.exit(1)
271
throw AssertionError() // Never reached
272
}
273
274
// ... other implementations using native APIs
275
}
276
```
277
278
## Custom Framework Integration
279
280
### Creating a Custom Testing Framework Integration
281
282
```kotlin
283
import kotlin.test.*
284
285
// Step 1: Implement the Asserter interface
286
class MyFrameworkAsserter : Asserter {
287
override fun fail(message: String?): Nothing {
288
MyTestFramework.reportFailure(message ?: "Test failed")
289
throw MyFrameworkException(message)
290
}
291
292
override fun fail(message: String?, cause: Throwable?): Nothing {
293
MyTestFramework.reportFailure(message ?: "Test failed", cause)
294
throw MyFrameworkException(message, cause)
295
}
296
297
override fun assertTrue(message: String?, actual: Boolean) {
298
if (!actual) {
299
MyTestFramework.reportBooleanFailure(message, expected = true, actual = false)
300
fail(message ?: "Expected true but was false")
301
}
302
}
303
304
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
305
if (expected != actual) {
306
MyTestFramework.reportEqualityFailure(message, expected, actual)
307
fail(message ?: "Expected <$expected> but was <$actual>")
308
}
309
}
310
311
// Implement remaining methods...
312
}
313
314
// Step 2: Create an AsserterContributor
315
class MyFrameworkAsserterContributor : AsserterContributor {
316
override fun contribute(): Asserter? {
317
return if (MyTestFramework.isActive()) {
318
MyFrameworkAsserter()
319
} else {
320
null
321
}
322
}
323
}
324
325
// Step 3: Register the contributor (usually done during framework initialization)
326
fun initializeMyFramework() {
327
val contributor = MyFrameworkAsserterContributor()
328
val customAsserter = contributor.contribute()
329
if (customAsserter != null) {
330
asserter = customAsserter
331
}
332
}
333
```
334
335
### Advanced Integration Features
336
337
```kotlin
338
// Enhanced asserter with additional framework-specific features
339
class EnhancedFrameworkAsserter : Asserter {
340
private val testContext = MyFramework.getCurrentTestContext()
341
342
override fun fail(message: String?): Nothing {
343
// Capture additional context
344
val stackTrace = Thread.currentThread().stackTrace
345
val testMethod = stackTrace.find { it.methodName.startsWith("test") }
346
347
MyFramework.reportDetailedFailure(
348
message = message,
349
testClass = testContext.testClass,
350
testMethod = testMethod?.methodName,
351
stackTrace = stackTrace
352
)
353
354
throw MyFrameworkException(message)
355
}
356
357
// Override other methods with enhanced reporting...
358
359
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
360
if (expected != actual) {
361
// Enhanced diff reporting
362
val diff = MyFramework.computeDiff(expected, actual)
363
MyFramework.reportEqualityFailure(
364
message = message,
365
expected = expected,
366
actual = actual,
367
diff = diff
368
)
369
fail(buildEqualityMessage(message, expected, actual, diff))
370
}
371
}
372
373
private fun buildEqualityMessage(
374
userMessage: String?,
375
expected: Any?,
376
actual: Any?,
377
diff: String
378
): String {
379
val base = userMessage ?: "Assertion failed"
380
return "$base\nExpected: $expected\nActual: $actual\nDiff:\n$diff"
381
}
382
}
383
```
384
385
## Error Handling and Framework Compatibility
386
387
The framework integration system handles various error scenarios gracefully:
388
389
- **Missing Framework**: Falls back to `DefaultAsserter` if no framework-specific asserter is available
390
- **Framework Conflicts**: Multiple asserter contributors can coexist; the first successful one is used
391
- **Runtime Switching**: The asserter can be changed during test execution for specialized testing scenarios
392
393
```kotlin
394
@Test
395
fun testFrameworkFallback() {
396
// This test works regardless of which testing framework is present
397
assertEquals("expected", computeValue())
398
assertTrue(isValid())
399
400
// The underlying asserter handles framework-specific reporting
401
}
402
```