0
# Asserter Interface
1
2
The core assertion interface that can be customized for different testing frameworks and platforms. The Asserter interface provides the foundation for all assertion operations in Kotlin Test.
3
4
## Capabilities
5
6
### Asserter Interface
7
8
The main interface for implementing custom assertion backends.
9
10
```kotlin { .api }
11
/**
12
* Abstracts the logic for performing assertions. Specific implementations can use
13
* JUnit, TestNG, or other assertion facilities.
14
*/
15
interface Asserter {
16
/**
17
* Fails the current test with the specified message
18
* @param message - The message to report
19
* @return Nothing (function never returns)
20
*/
21
fun fail(message: String?): Nothing
22
23
/**
24
* Fails the current test with the specified message and cause exception
25
* @param message - The message to report
26
* @param cause - The exception to set as the root cause of the reported failure
27
* @return Nothing (function never returns)
28
*/
29
fun fail(message: String?, cause: Throwable?): Nothing
30
31
/**
32
* Asserts that the specified value is true
33
* @param lazyMessage - Function to return a message to report if the assertion fails
34
* @param actual - Boolean value to check
35
*/
36
fun assertTrue(lazyMessage: () -> String?, actual: Boolean): Unit
37
38
/**
39
* Asserts that the specified value is true
40
* @param message - The message to report if the assertion fails
41
* @param actual - Boolean value to check
42
*/
43
fun assertTrue(message: String?, actual: Boolean): Unit
44
45
/**
46
* Asserts that the specified values are equal
47
* @param message - The message to report if the assertion fails
48
* @param expected - Expected value
49
* @param actual - Actual value
50
*/
51
fun assertEquals(message: String?, expected: Any?, actual: Any?): Unit
52
53
/**
54
* Asserts that the specified values are not equal
55
* @param message - The message to report if the assertion fails
56
* @param illegal - Value that should not match
57
* @param actual - Actual value
58
*/
59
fun assertNotEquals(message: String?, illegal: Any?, actual: Any?): Unit
60
61
/**
62
* Asserts that the specified values are the same instance
63
* @param message - The message to report if the assertion fails
64
* @param expected - Expected object reference
65
* @param actual - Actual object reference
66
*/
67
fun assertSame(message: String?, expected: Any?, actual: Any?): Unit
68
69
/**
70
* Asserts that the specified values are not the same instance
71
* @param message - The message to report if the assertion fails
72
* @param illegal - Object reference that should not match
73
* @param actual - Actual object reference
74
*/
75
fun assertNotSame(message: String?, illegal: Any?, actual: Any?): Unit
76
77
/**
78
* Asserts that the specified value is null
79
* @param message - The message to report if the assertion fails
80
* @param actual - Value to check for nullness
81
*/
82
fun assertNull(message: String?, actual: Any?): Unit
83
84
/**
85
* Asserts that the specified value is not null
86
* @param message - The message to report if the assertion fails
87
* @param actual - Value to check for non-nullness
88
*/
89
fun assertNotNull(message: String?, actual: Any?): Unit
90
}
91
```
92
93
### AsserterContributor Interface
94
95
Interface for providing Asserter instances based on context.
96
97
```kotlin { .api }
98
/**
99
* Checks applicability and provides Asserter instance
100
*/
101
interface AsserterContributor {
102
/**
103
* Provides Asserter instance or null depending on the current context
104
* @return Asserter instance or null if not applicable
105
*/
106
fun contribute(): Asserter?
107
}
108
```
109
110
### DefaultAsserter Object
111
112
Default implementation of the Asserter interface.
113
114
```kotlin { .api }
115
/**
116
* Default Asserter implementation to avoid dependency on JUnit or TestNG
117
*/
118
object DefaultAsserter : Asserter
119
```
120
121
### Current Asserter Property
122
123
Global property to access the current asserter instance.
124
125
```kotlin { .api }
126
/**
127
* Current adapter providing assertion implementations
128
* Gets the current asserter or looks up an available one
129
*/
130
val asserter: Asserter
131
```
132
133
## Usage Examples
134
135
### Using the Global Asserter
136
137
```kotlin
138
import kotlin.test.*
139
140
@Test
141
fun testUsingGlobalAsserter() {
142
// The global asserter is used automatically by assertion functions
143
val result = performCalculation()
144
145
// These functions delegate to the current asserter
146
assertTrue(result > 0)
147
assertEquals(42, result)
148
assertNotNull(result)
149
150
// You can also use the asserter directly (though not typically needed)
151
asserter.assertTrue("Result should be positive", result > 0)
152
asserter.assertEquals("Should equal 42", 42, result)
153
}
154
```
155
156
### Creating Custom Asserter
157
158
```kotlin
159
class CustomAsserter(private val testName: String) : Asserter {
160
override fun fail(message: String?): Nothing {
161
val fullMessage = "[$testName] ${message ?: "Test failed"}"
162
throw AssertionError(fullMessage)
163
}
164
165
override fun fail(message: String?, cause: Throwable?): Nothing {
166
val fullMessage = "[$testName] ${message ?: "Test failed"}"
167
throw AssertionError(fullMessage, cause)
168
}
169
170
override fun assertTrue(message: String?, actual: Boolean) {
171
if (!actual) {
172
fail(message ?: "Expected value to be true")
173
}
174
}
175
176
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
177
if (expected != actual) {
178
fail("${message ?: "Values should be equal"}: expected <$expected>, actual <$actual>")
179
}
180
}
181
182
override fun assertNotEquals(message: String?, illegal: Any?, actual: Any?) {
183
if (illegal == actual) {
184
fail("${message ?: "Values should not be equal"}: illegal value <$actual>")
185
}
186
}
187
188
override fun assertSame(message: String?, expected: Any?, actual: Any?) {
189
if (expected !== actual) {
190
fail("${message ?: "References should be same"}: expected <$expected>, actual <$actual>")
191
}
192
}
193
194
override fun assertNotSame(message: String?, illegal: Any?, actual: Any?) {
195
if (illegal === actual) {
196
fail("${message ?: "References should not be same"}: illegal reference <$actual>")
197
}
198
}
199
200
override fun assertNull(message: String?, actual: Any?) {
201
if (actual != null) {
202
fail("${message ?: "Value should be null"}: actual <$actual>")
203
}
204
}
205
206
override fun assertNotNull(message: String?, actual: Any?) {
207
if (actual == null) {
208
fail(message ?: "Value should not be null")
209
}
210
}
211
}
212
```
213
214
### Creating Custom AsserterContributor
215
216
```kotlin
217
class LoggingAsserterContributor : AsserterContributor {
218
override fun contribute(): Asserter? {
219
// Only provide the logging asserter in debug mode
220
return if (isDebugMode()) {
221
LoggingAsserter()
222
} else {
223
null
224
}
225
}
226
}
227
228
class LoggingAsserter : Asserter {
229
private fun log(operation: String, message: String?) {
230
println("[ASSERT] $operation: ${message ?: "no message"}")
231
}
232
233
override fun fail(message: String?): Nothing {
234
log("FAIL", message)
235
throw AssertionError(message)
236
}
237
238
override fun fail(message: String?, cause: Throwable?): Nothing {
239
log("FAIL", "$message (caused by: ${cause?.message})")
240
throw AssertionError(message, cause)
241
}
242
243
override fun assertTrue(message: String?, actual: Boolean) {
244
log("ASSERT_TRUE", message)
245
if (!actual) {
246
throw AssertionError(message ?: "Expected true")
247
}
248
}
249
250
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
251
log("ASSERT_EQUALS", "$message: expected=$expected, actual=$actual")
252
if (expected != actual) {
253
throw AssertionError("Expected <$expected>, actual <$actual>")
254
}
255
}
256
257
// ... implement other methods with logging
258
}
259
```
260
261
## Platform-Specific Asserter Implementations
262
263
### JUnit Asserter Integration
264
265
```kotlin
266
// This is how kotlin-test integrates with JUnit internally
267
class JUnitAsserter : Asserter {
268
override fun fail(message: String?): Nothing {
269
org.junit.Assert.fail(message)
270
throw AssertionError() // Never reached, but needed for Nothing return type
271
}
272
273
override fun assertTrue(message: String?, actual: Boolean) {
274
org.junit.Assert.assertTrue(message, actual)
275
}
276
277
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
278
org.junit.Assert.assertEquals(message, expected, actual)
279
}
280
281
// ... other methods delegate to JUnit assertions
282
}
283
```
284
285
### TestNG Asserter Integration
286
287
```kotlin
288
class TestNGAsserter : Asserter {
289
override fun fail(message: String?): Nothing {
290
org.testng.Assert.fail(message)
291
throw AssertionError() // Never reached
292
}
293
294
override fun assertTrue(message: String?, actual: Boolean) {
295
org.testng.Assert.assertTrue(actual, message)
296
}
297
298
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
299
org.testng.Assert.assertEquals(actual, expected, message)
300
}
301
302
// ... other methods delegate to TestNG assertions
303
}
304
```
305
306
### Custom Test Framework Integration
307
308
```kotlin
309
class MyFrameworkAsserter : Asserter {
310
override fun fail(message: String?): Nothing {
311
MyTestFramework.reportFailure(message ?: "Test failed")
312
throw MyTestFramework.TestFailedException(message)
313
}
314
315
override fun assertTrue(message: String?, actual: Boolean) {
316
if (!actual) {
317
MyTestFramework.reportAssertion("assertTrue", message, false)
318
fail(message ?: "Expected true")
319
} else {
320
MyTestFramework.reportAssertion("assertTrue", message, true)
321
}
322
}
323
324
// ... implement other methods to integrate with your framework
325
}
326
```
327
328
## Advanced Usage Patterns
329
330
### Temporary Asserter Override
331
332
```kotlin
333
@Test
334
fun testWithCustomAsserter() {
335
val originalAsserter = asserter
336
val customAsserter = CustomAsserter("MyTest")
337
338
try {
339
// Temporarily override the asserter
340
overrideAsserter(customAsserter)
341
342
// All assertions now use the custom asserter
343
assertTrue(true) // Will use CustomAsserter
344
assertEquals(42, 42) // Will use CustomAsserter
345
346
} finally {
347
// Restore original asserter
348
overrideAsserter(originalAsserter)
349
}
350
}
351
352
// Helper function to override asserter (internal API)
353
fun overrideAsserter(newAsserter: Asserter): Asserter {
354
// This uses internal kotlin-test API
355
return kotlin.test.overrideAsserter(newAsserter) ?: DefaultAsserter
356
}
357
```
358
359
### Asserter Chain
360
361
```kotlin
362
class ChainedAsserter(private val asserters: List<Asserter>) : Asserter {
363
override fun fail(message: String?): Nothing {
364
// Fail using the first asserter in the chain
365
asserters.firstOrNull()?.fail(message) ?: throw AssertionError(message)
366
}
367
368
override fun assertTrue(message: String?, actual: Boolean) {
369
// Execute assertion on all asserters in chain
370
for (asserter in asserters) {
371
asserter.assertTrue(message, actual)
372
}
373
}
374
375
// ... implement other methods to delegate to all asserters
376
}
377
378
@Test
379
fun testWithChainedAsserters() {
380
val loggingAsserter = LoggingAsserter()
381
val junitAsserter = JUnitAsserter()
382
val chainedAsserter = ChainedAsserter(listOf(loggingAsserter, junitAsserter))
383
384
overrideAsserter(chainedAsserter)
385
386
// This will both log the assertion AND use JUnit's assertion
387
assertTrue(5 > 3)
388
}
389
```
390
391
## Platform-Specific Utilities
392
393
### currentStackTrace Function (JVM Only)
394
395
**⚠️ JVM Platform Only** - This function is only available when running tests on the JVM platform.
396
397
Returns the current stack trace as an array of stack trace elements for debugging and diagnostic purposes.
398
399
```kotlin { .api }
400
/**
401
* Returns an array of stack trace elements, each representing one stack frame
402
* The first element represents the top of the stack (where currentStackTrace was called)
403
* @return Array of StackTraceElement representing the call stack
404
*/
405
inline fun currentStackTrace(): Array<StackTraceElement>
406
```
407
408
**Usage Examples:**
409
410
```kotlin
411
import kotlin.test.*
412
413
@Test
414
fun testStackTraceCapture() {
415
// Capture stack trace at current location
416
val stackTrace = currentStackTrace()
417
418
// Examine the top frame (where currentStackTrace was called)
419
val topFrame = stackTrace[0]
420
println("Called from: ${topFrame.fileName}:${topFrame.lineNumber}")
421
println("Method: ${topFrame.methodName}")
422
println("Class: ${topFrame.className}")
423
424
// Verify we captured the right location
425
assertEquals("AssertionTests.kt", topFrame.fileName)
426
assertTrue(topFrame.lineNumber > 0)
427
}
428
429
// Custom diagnostic assertion using stack trace
430
fun assertWithLocation(condition: Boolean, message: String) {
431
if (!condition) {
432
val location = currentStackTrace()[0]
433
fail("$message at ${location.fileName}:${location.lineNumber}")
434
}
435
}
436
437
@Test
438
fun testCustomDiagnosticAssertion() {
439
val value = 42
440
441
// This will provide detailed location info if it fails
442
assertWithLocation(value == 42, "Value should be 42")
443
444
// Example of failure (commented out)
445
// assertWithLocation(value == 99, "This will show exact location")
446
}
447
448
// Advanced: Custom test framework integration
449
class DetailedAsserter : Asserter {
450
override fun fail(message: String?): Nothing {
451
val location = currentStackTrace()[1] // Skip this frame
452
throw AssertionError("$message\n at ${location.className}.${location.methodName}(${location.fileName}:${location.lineNumber})")
453
}
454
455
override fun assertTrue(message: String?, actual: Boolean) {
456
if (!actual) {
457
fail(message ?: "Assertion failed")
458
}
459
}
460
461
// ... implement other Asserter methods
462
}
463
464
@Test
465
fun testDetailedStackTraceDiagnostics() {
466
// This custom asserter will provide detailed location info
467
val detailedAsserter = DetailedAsserter()
468
469
try {
470
detailedAsserter.assertTrue("This should pass", true)
471
detailedAsserter.assertTrue("This will fail with location", false)
472
} catch (e: AssertionError) {
473
// The error message will include precise location information
474
assertContains(e.message ?: "", "AssertionTests.kt")
475
}
476
}
477
```
478
479
**Platform Notes:**
480
- **Availability**: Only available on JVM platform
481
- **Performance**: Minimal overhead as it uses Java's built-in stack trace mechanism
482
- **Use Cases**: Debugging, custom error reporting, diagnostic utilities
483
- **Stack Frame Structure**: First element [0] is the location where `currentStackTrace()` was called
484
- **Integration**: Used internally by the `todo()` function for location reporting
485
486
This function is particularly useful for building custom assertion utilities, debugging test failures, and creating diagnostic tools that need to report precise location information.