You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Kotlin suspend function detection doesn't work when JUnit and test method are in a separate ClassLoader #5375
When using JUnit 5 in Quarkus, then tests annotated with @QuarkusTest can't take advantage of the new Kotlin suspend function support.
Although there is needs to be work on Quarkus as well for this to work, currently progress is blocked by JUnit not detecting the suspend methods and instead skipping the test method with a warning like:
2026-02-13 15:24:22,254 WARNING [org.junit.platform.launcher.core.DiscoveryIssueNotifier] (main) TestEngine with ID 'junit-jupiter' encountered a non-critical issue during test discovery:
(1) [WARNING] @Test method 'public final java.lang.Object org.acme.QuarkusSuspendTest.suspendingTestShouldRun(kotlin.coroutines.Continuation<? super kotlin.Unit>)' must not return a value. It will not be executed.
Source: MethodSource [className = 'org.acme.QuarkusSuspendTest', methodName = 'suspendingTestShouldRun', methodParameterTypes = 'kotlin.coroutines.Continuation']
at org.acme.QuarkusSuspendTest.suspendingTestShouldRun(SourceFile:0)
[INFO]
I am using the latest Quarkus version which brings in JUnit 6.0.2
https://github.com/geoand/junit-suspend-classloader-reproducer does not use Quarkus at all, but instead adds only the necessary plumbing for JUnit that effectively does what Quarkus does during testing when it comes to class loading.
This reproducer exhibits the same problem I mentioned in the description.
Is there documentation about Quarkus' classloader structure? I would like to know why classes from kotlin-stdlib would be loaded multiple times. Isn't that unnecessary and potentially wasteful?
The reason this particular problem happens is that only a very small set of dependencies is loaded by the JDK ClassLoader (JUnit being one of them) while all the rest are loaded by the Quarkus ClassLoader. Ideally, all classes would be loaded by Quarkus ClassLoaders, but for various reasons, that simply isn't possible.
via proxy and cross-classloader, without touching the existing discovery/execution logic. and on quarkus side, it's just a single Invoker implementation
Right, it's clever for sure!
So the overall surface area is fairly small i think?
That's up to the JUnit folks to decide, I'm just an integrator :)
we're still waiting on feedback on #5375 (comment) before we can decide how to proceed.
@marcphilipp ok, i ran 4 experiments using this reproducer to verify:
Original reproducer (only kotlin.* isolated) + JUnit 6.0.3
Original reproducer (only kotlin.* isolated) + my PR snapshot
With your change (kotlin.* + org.acme.* isolated) + JUnit 6.0.3
With your change (kotlin.* + org.acme.* isolated) + my PR snapshot
The only modification I made to the reproducer, was replacing the dependency of JUnit with the snapshot built from my pr. The snapshot jars are bundled in local-m2-repo(999.999.999-SNAPSHOT) so it runs out of the box.
If you would like us to be able to process this issue, please provide the requested information. If the information is not provided within the next 3 weeks, we will be unable to proceed and this issue will be closed.
Team decision: In order to use JUnit's Kotlin-specific features (like suspend function support), JUnit needs to be able to load Kotlin classes (kotlin-reflect etc.). As the approach in geoand#1 shows, using Java reflection to use Kotlin reflection is heavy-handed, will likely be brittle, and more complexity than we're willing to maintain.
Activity
marcphilipp commentedon Feb 13, 2026
Could you please extract the relevant parts of Quarkus' extension into a standalone extension in the reproducer?
geoand commentedon Feb 14, 2026
https://github.com/geoand/junit-suspend-classloader-reproducer does not use Quarkus at all, but instead adds only the necessary plumbing for JUnit that effectively does what Quarkus does during testing when it comes to class loading.
This reproducer exhibits the same problem I mentioned in the description.
With #5373, the test is executed as expected
marcphilipp commentedon Feb 14, 2026
Is there documentation about Quarkus' classloader structure? I would like to know why classes from kotlin-stdlib would be loaded multiple times. Isn't that unnecessary and potentially wasteful?
geoand commentedon Feb 14, 2026
We do have https://quarkus.io/guides/class-loading-reference, but that is not exactly accurate for testing after the latest changes made by @holly-cummins.
The reason this particular problem happens is that only a very small set of dependencies is loaded by the JDK ClassLoader (JUnit being one of them) while all the rest are loaded by the Quarkus ClassLoader. Ideally, all classes would be loaded by Quarkus ClassLoaders, but for various reasons, that simply isn't possible.
40 remaining items
geoand commentedon May 13, 2026
Right, it's clever for sure!
That's up to the JUnit folks to decide, I'm just an integrator :)
marcphilipp commentedon May 15, 2026
@tdiant Thanks for your efforts!
However, we're still waiting on feedback on #5375 (comment) before we can decide how to proceed.
tdiant commentedon May 15, 2026
@marcphilipp ok, i ran 4 experiments using this reproducer to verify:
kotlin.*isolated) + JUnit 6.0.3kotlin.*isolated) + my PR snapshotkotlin.*+org.acme.*isolated) + JUnit 6.0.3kotlin.*+org.acme.*isolated) + my PR snapshotThe only modification I made to the reproducer, was replacing the dependency of JUnit with the snapshot built from my pr. The snapshot jars are bundled in
local-m2-repo(999.999.999-SNAPSHOT) so it runs out of the box.Does this cover what you were looking for?
tdiant commentedon May 15, 2026
junit-suspend-classloader-reproducer2.zip
@marcphilipp here is the reproducer
github-actions commentedon May 30, 2026
If you would like us to be able to process this issue, please provide the requested information. If the information is not provided within the next 3 weeks, we will be unable to proceed and this issue will be closed.
marcphilipp commentedon Sep 25, 2026
Team decision: In order to use JUnit's Kotlin-specific features (like suspend function support), JUnit needs to be able to load Kotlin classes (kotlin-reflect etc.). As the approach in geoand#1 shows, using Java reflection to use Kotlin reflection is heavy-handed, will likely be brittle, and more complexity than we're willing to maintain.