Skip to content

JUnit5TestEnvironmentInitializer implicitly depends on JUnit 4 classes #2045

@PawelLipski

Description

@PawelLipski

What happened?

In subprojects that:

  1. have org.jetbrains.intellij.platform.module plugin enabled AND
  2. have JUnit 5 (useJUnitPlatform()) tests

JUnit 4 is still implicitly required on the classpath, or a ClassNotFoundException for JUnit 4 classes crashes them before they have a chance to run.

Specifically, JUnit5TestEnvironmentInitializer.launcherSessionOpened calls TestEnvironmentKt.initializeTestEnvironment, which calls Logger.setFactory(TestLoggerFactory::class.java), and TestLoggerFactory depends on JUnit 4 classes.

The workaround is to add JUnit4 classes onto the runtime classpath, but this shouldn't be necessary.

Relevant log output or stack trace

Gradle Test Executor 9 FAILED
    org.gradle.api.internal.tasks.testing.TestSuiteExecutionException: Could not start Gradle Test Executor 9: org/junit/rules/TestRule
        at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.startProcessing(SuiteTestClassProcessor.java:46)
        at [email protected]/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at [email protected]/java.lang.reflect.Method.invoke(Method.java:580)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
        at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:92)
        at jdk.proxy1/jdk.proxy1.$Proxy4.startProcessing(Unknown Source)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker$1.run(TestWorker.java:168)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:132)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:103)
        at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:63)
        at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
        at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:72)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
        at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)

        Caused by:
        java.lang.NoClassDefFoundError: org/junit/rules/TestRule
            at java.base/java.lang.Class.getDeclaredConstructors0(Native Method)
            at java.base/java.lang.Class.privateGetDeclaredConstructors(Class.java:3549)
            at java.base/java.lang.Class.getConstructor0(Class.java:3754)
            at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2930)
            at com.intellij.openapi.diagnostic.Logger.setFactory(Logger.java:71)
            at com.intellij.testFramework.common.TestEnvironmentKt.initializeTestEnvironment(testEnvironment.kt:31)
            at com.intellij.testFramework.junit5.impl.JUnit5TestEnvironmentInitializer.launcherSessionOpened(JUnit5TestEnvironmentInitializer.kt:15)
            at org.junit.platform.launcher.core.DefaultLauncherSession.<init>(DefaultLauncherSession.java:71)
            at org.junit.platform.launcher.core.LauncherFactory.openSession(LauncherFactory.java:101)
            at org.junit.platform.launcher.core.LauncherFactory.openSession(LauncherFactory.java:83)
            at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$BackwardsCompatibleLauncherSession.open(JUnitPlatformTestClassProcessor.java:334)
            at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.createTestExecutor(JUnitPlatformTestClassProcessor.java:95)
            at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.startProcessing(AbstractJUnitTestClassProcessor.java:48)
            at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.startProcessing(SuiteTestClassProcessor.java:43)
            ... 16 more

            Caused by:
            java.lang.ClassNotFoundException: org.junit.rules.TestRule
                at com.intellij.util.lang.UrlClassLoader.findClass(UrlClassLoader.java:259)
                at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
                at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
                ... 30 more

Steps to reproduce

  1. Check out VirtusLab/git-machete-intellij-plugin at PR #2166
  2. Switch Java to 21 locally
  3. Run ./gradlew --debug :frontend:base:test | grep -C50 ClassNotFound
  4. Remove the latest commit (git reset --keep HEAD~), thus restoring JUnit4 dependency
  5. Test should pass now

Gradle IntelliJ Plugin version

2.10.1 (although at least 2.4.0 was affected, if not earlier)

Gradle version

9.0.0

Operating System

macOS

Link to build, i.e. failing GitHub Action job

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions