Skip to content

Kotlin suspend function detection doesn't work when JUnit and test method are in a separate ClassLoader #5375

Closed as not planned

Description

@geoand

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

Steps to reproduce

With the following reproducer:

code-with-quarkus.zip

simply execute mvn test

Activity

  1. added theissue type on Feb 13, 2026
  2. marcphilipp commented on Feb 13, 2026

    @marcphilipp
    Member

    Could you please extract the relevant parts of Quarkus' extension into a standalone extension in the reproducer?

  3. geoand commented on Feb 14, 2026

    @geoand
    Author

    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

  4. marcphilipp commented on Feb 14, 2026

    @marcphilipp
    Member

    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?

  5. geoand commented on Feb 14, 2026

    @geoand
    Author

    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.

  6. 40 remaining items

  7. geoand commented on May 13, 2026

    @geoand
    Author

    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 :)

  8. marcphilipp commented on May 15, 2026

    @marcphilipp
    Member

    @tdiant Thanks for your efforts!

    However, we're still waiting on feedback on #5375 (comment) before we can decide how to proceed.

  9. tdiant commented on May 15, 2026

    @tdiant

    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:

    1. Original reproducer (only kotlin.* isolated) + JUnit 6.0.3
    Image
    1. Original reproducer (only kotlin.* isolated) + my PR snapshot
    Image
    1. With your change (kotlin.* + org.acme.* isolated) + JUnit 6.0.3
    Image
    1. With your change (kotlin.* + org.acme.* isolated) + my PR snapshot
    Image

    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.

    Does this cover what you were looking for?

  10. tdiant commented on May 15, 2026

    @tdiant
  11. github-actions commented on May 30, 2026

    @github-actions

    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.

  12. marcphilipp commented on Sep 25, 2026

    @marcphilipp
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions