Skip to content

Commit d2c0d8e

Browse files
author
Matthew de Detrich
committed
Add assertThrows variants which accept exceptions as values
Signed-off-by: Matthew de Detrich <matthew.dedetrich@gls-itservices.com>
1 parent e49e70c commit d2c0d8e

3 files changed

Lines changed: 327 additions & 1 deletion

File tree

documentation/modules/ROOT/partials/release-notes/release-notes-6.2.0-M1.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ repository on GitHub.
3232
* When using a third-party engine that uses the `junit-` prefix a discovery issue is
3333
emitted.
3434
* `junit-platform-console-standalone` is now part of the `junit-bom`
35+
* The `org.junit.jupiter.api.assertThrows` Kotlin API and its related functions have
36+
added variants that use an exception class as a value rather than a type parameter.
37+
This is to primarily to address the current issue/s when trying to use
38+
`@ParameterizedTest` that produces exceptions as values.
3539

3640
[[v6.2.0-M1-junit-jupiter]]
3741
=== JUnit Jupiter

junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,39 @@ inline fun <reified T : Throwable> assertThrows(executable: () -> Unit): T {
285285
}
286286
}
287287

288+
/**
289+
* Example usage:
290+
* ```kotlin
291+
* val exception = assertThrows(IllegalArgumentException::class.java) {
292+
* throw IllegalArgumentException("Talk to a duck")
293+
* }
294+
* assertEquals("Talk to a duck", exception.message)
295+
* ```
296+
*
297+
* This version of assertThrows is intended to be used in situations where reified Throwable's cannot be used,
298+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
299+
* @see Assertions.assertThrows
300+
*/
301+
inline fun <T : Throwable> assertThrows(
302+
expectedType: Class<T>,
303+
executable: () -> Unit
304+
): T {
305+
// no contract for `executable` because it is expected to throw an exception instead
306+
// of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748)
307+
val throwable: Throwable? =
308+
try {
309+
executable()
310+
} catch (caught: Throwable) {
311+
caught
312+
} as? Throwable
313+
314+
return Assertions.assertThrows(expectedType) {
315+
if (throwable != null) {
316+
throw throwable
317+
}
318+
}
319+
}
320+
288321
/**
289322
* Example usage:
290323
* ```kotlin
@@ -300,6 +333,25 @@ inline fun <reified T : Throwable> assertThrows(
300333
executable: () -> Unit
301334
): T = assertThrows({ message }, executable)
302335

336+
/**
337+
* Example usage:
338+
* ```kotlin
339+
* val exception = assertThrows(IllegalArgumentException::class.java, "Should throw an Exception") {
340+
* throw IllegalArgumentException("Talk to a duck")
341+
* }
342+
* assertEquals("Talk to a duck", exception.message)
343+
* ```
344+
*
345+
* This version of assertThrows is intended to be used in situations where reified Throwable's cannot be used,
346+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
347+
* @see Assertions.assertThrows
348+
*/
349+
inline fun <T : Throwable> assertThrows(
350+
expectedType: Class<T>,
351+
message: String,
352+
executable: () -> Unit
353+
): T = assertThrows(expectedType, { message }, executable)
354+
303355
/**
304356
* Example usage:
305357
* ```kotlin
@@ -339,6 +391,49 @@ inline fun <reified T : Throwable> assertThrows(
339391
)
340392
}
341393

394+
/**
395+
* Example usage:
396+
* ```kotlin
397+
* val exception = assertThrows(IllegalArgumentException::class.java, { "Should throw an Exception" }) {
398+
* throw IllegalArgumentException("Talk to a duck")
399+
* }
400+
* assertEquals("Talk to a duck", exception.message)
401+
* ```
402+
*
403+
* This version of assertThrows is intended to be used in situations where reified Throwable's cannot be used,
404+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
405+
* @see Assertions.assertThrows
406+
*/
407+
@OptIn(ExperimentalContracts::class)
408+
inline fun <T : Throwable> assertThrows(
409+
expectedType: Class<T>,
410+
noinline message: () -> String,
411+
executable: () -> Unit
412+
): T {
413+
contract {
414+
callsInPlace(message, AT_MOST_ONCE)
415+
// no contract for `executable` because it is expected to throw an exception instead
416+
// of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748)
417+
}
418+
419+
val throwable: Throwable? =
420+
try {
421+
executable()
422+
} catch (caught: Throwable) {
423+
caught
424+
} as? Throwable
425+
426+
return Assertions.assertThrows(
427+
expectedType,
428+
{
429+
if (throwable != null) {
430+
throw throwable
431+
}
432+
},
433+
message
434+
)
435+
}
436+
342437
/**
343438
* Example usage:
344439
* ```kotlin
@@ -366,6 +461,39 @@ inline fun <reified T : Throwable> assertThrowsExactly(executable: () -> Unit):
366461
}
367462
}
368463

464+
/**
465+
* Example usage:
466+
* ```kotlin
467+
* val exception = assertThrows(IllegalArgumentException::class.java) {
468+
* throw IllegalArgumentException("Talk to a duck")
469+
* }
470+
* assertEquals("Talk to a duck", exception.message)
471+
* ```
472+
*
473+
* This version of assertThrowsExactly is intended to be used in situations where reified Throwable's cannot be used,
474+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
475+
* @see Assertions.assertThrowsExactly
476+
*/
477+
inline fun <T : Throwable> assertThrowsExactly(
478+
expectedType: Class<T>,
479+
executable: () -> Unit
480+
): T {
481+
// no contract for `executable` because it is expected to throw an exception instead
482+
// of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748)
483+
val throwable: Throwable? =
484+
try {
485+
executable()
486+
} catch (caught: Throwable) {
487+
caught
488+
} as? Throwable
489+
490+
return Assertions.assertThrowsExactly(expectedType) {
491+
if (throwable != null) {
492+
throw throwable
493+
}
494+
}
495+
}
496+
369497
/**
370498
* Example usage:
371499
* ```kotlin
@@ -381,6 +509,25 @@ inline fun <reified T : Throwable> assertThrowsExactly(
381509
executable: () -> Unit
382510
): T = assertThrowsExactly({ message }, executable)
383511

512+
/**
513+
* Example usage:
514+
* ```kotlin
515+
* val exception = assertThrowsExactly(IllegalArgumentException::class.java, "Should throw an Exception") {
516+
* throw IllegalArgumentException("Talk to a duck")
517+
* }
518+
* assertEquals("Talk to a duck", exception.message)
519+
* ```
520+
*
521+
* This version of assertThrowsExactly is intended to be used in situations where reified Throwable's cannot be used,
522+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
523+
* @see Assertions.assertThrowsExactly
524+
*/
525+
inline fun <T : Throwable> assertThrowsExactly(
526+
expectedType: Class<T>,
527+
message: String,
528+
executable: () -> Unit
529+
): T = assertThrowsExactly(expectedType, { message }, executable)
530+
384531
/**
385532
* Example usage:
386533
* ```kotlin
@@ -420,6 +567,49 @@ inline fun <reified T : Throwable> assertThrowsExactly(
420567
)
421568
}
422569

570+
/**
571+
* Example usage:
572+
* ```kotlin
573+
* val exception = assertThrowsExactly(IllegalArgumentException::class.java, { "Should throw an Exception" }) {
574+
* throw IllegalArgumentException("Talk to a duck")
575+
* }
576+
* assertEquals("Talk to a duck", exception.message)
577+
* ```
578+
*
579+
* This version of assertThrowsExactly is intended to be used in situations where reified Throwable's cannot be used,
580+
* i.e. when using a @ParameterizedTest that provides exception classes as values.
581+
* @see Assertions.assertThrowsExactly
582+
*/
583+
@OptIn(ExperimentalContracts::class)
584+
inline fun <T : Throwable> assertThrowsExactly(
585+
expectedType: Class<T>,
586+
noinline message: () -> String,
587+
executable: () -> Unit
588+
): T {
589+
contract {
590+
callsInPlace(message, AT_MOST_ONCE)
591+
// no contract for `executable` because it is expected to throw an exception instead
592+
// of being executed completely (see https://youtrack.jetbrains.com/issue/KT-27748)
593+
}
594+
595+
val throwable: Throwable? =
596+
try {
597+
executable()
598+
} catch (caught: Throwable) {
599+
caught
600+
} as? Throwable
601+
602+
return Assertions.assertThrowsExactly(
603+
expectedType,
604+
{
605+
if (throwable != null) {
606+
throw throwable
607+
}
608+
},
609+
message
610+
)
611+
}
612+
423613
/**
424614
* Example usage:
425615
* ```kotlin

0 commit comments

Comments
 (0)