Skip to content

Add assertThrows variants which accept exceptions as values#5819

Open
mdedetrich wants to merge 1 commit into
junit-team:mainfrom
mdedetrich:assert-throws-exceptions-as-value
Open

Add assertThrows variants which accept exceptions as values#5819
mdedetrich wants to merge 1 commit into
junit-team:mainfrom
mdedetrich:assert-throws-exceptions-as-value

Conversation

@mdedetrich

@mdedetrich mdedetrich commented Jun 30, 2026

Copy link
Copy Markdown

Currently there exists org.junit.jupiter.api.assertThrows and its various variants to be used with JUnit and Kotlin that are also compatible with coroutines (i.e. suspend func). The current design uses reified inline functions, which generally work aside from one situation, specifically

  1. You are using @ParameterizedTest that produces exceptions classes as values and you intend to use assertThrows on those exception values.
  2. The function/method you are testing is a kotlin coroutine (suspend func)

In this case, the current org.junit.jupiter.api.assertThrows doesn't work because in order to use it you would have to make your test function (the one annotated with @ParameterizedTest) an inline func with a reified T: Throwable however this won't be picked up by JUnit as @ParameterizedTest uses reflection.

This PR adds variants of the currently existing org.junit.jupiter.api.assertThrows that have an expectedType: Class<T> as the first parameter (which is the same convention as org.junit.jupiter.api.Assertions.assertThrows) but since these added variants are inline fun, functions/methods used in the body can be suspend func (this is verified with the added tests).

The current implementation is a bit of boilerplate however this is inevitable to a degree since we cannot use the currently existing org.junit.jupiter.api.assertThrows and its variants implementations as they only accept reified T: Throwable which then defeats the purpose of what we are trying to achieve.


I hereby agree to the terms of the JUnit Contributor License Agreement.


Definition of Done

@marcphilipp

Copy link
Copy Markdown
Member

@mdedetrich Can't you use Assertions.assertThrows directly?

@mdedetrich

mdedetrich commented Jul 1, 2026

Copy link
Copy Markdown
Author

@mdedetrich Can't you use Assertions.assertThrows directly?

Not with a kotlin suspend function that you are asserting, thats the precise issue. It will fail to compile for the reasons I stated in the PR. Kotlin suspend only works if the assertThrow definitions are inline func (which Assertions.assertThrows is not since its written in Java) or if the block parameter argument has suspend func () -> definition.

Of course you could just do

Assertions.assertThrows(IllegalArgumentException::class.java) {
  runBlocking {
    someKotlinSuspendFunc()
  }
}

But one of the whole point of org.junit.jupiter.api.* assert functions existing is so that they can work with kotlin coroutines directly without the using of runBlocking/runTest.

I have just rebased the PR against latest main to resolve conflicts.

Comment thread junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt Outdated
@marcphilipp

Copy link
Copy Markdown
Member

Kotlin suspend only works if the assertThrow definitions are inline func

Sorry for making you re-explain it. I didn't read carefully enough. 😬

@testlens-app

This comment has been minimized.

Signed-off-by: Matthew de Detrich <matthew.dedetrich@gls-itservices.com>
@mdedetrich mdedetrich force-pushed the assert-throws-exceptions-as-value branch from 95ba98b to d3494e9 Compare July 1, 2026 07:58
@mdedetrich mdedetrich requested a review from marcphilipp July 1, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants