[junit6] add support for JUnit6 external library resolver IDEA-379951

GitOrigin-RevId: bc53345f7cac250c6f60a42481ac4958b8af6c3f
This commit is contained in:
Aleksey Dobrynin
2025-10-07 14:43:02 +00:00
committed by intellij-monorepo-bot
parent c55e165442
commit 125d91b0ff
6 changed files with 84 additions and 29 deletions
+2 -1
View File
@@ -6,7 +6,7 @@
Supports <a href="https://junit.org">JUnit</a> tests.
The following features are available:
<ul>
<li>Ability to create JUnit 3.x, JUnit 4.x or JUnit 5.x tests.</li>
<li>Ability to create JUnit 3.x, JUnit 4.x, JUnit 5.x or JUnit 6.x tests.</li>
<li>Navigation between a test and test subject.</li>
<li>Running tests.</li>
<li>Viewing test results in the dedicated Test Runner tab of the Run tool window.</li>
@@ -62,6 +62,7 @@
<programRunner implementation="com.intellij.execution.junit.JUnitDebuggerRunner"/>
<codeInsight.externalLibraryResolver implementation="com.intellij.execution.junit.codeInsight.JUnitExternalLibraryResolver"/>
<codeInsight.externalLibraryResolver implementation="com.intellij.execution.junit.codeInsight.JUnit5ExternalLibraryResolver"/>
<codeInsight.externalLibraryResolver implementation="com.intellij.execution.junit.codeInsight.JUnit6ExternalLibraryResolver"/>
<junitListener implementation="com.intellij.junit4.JUnitTestDiscoveryListener"/>
<runConfigurationProducer implementation="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer"/>
<testDiscoveryProducer implementation="com.intellij.execution.testDiscovery.LocalTestDiscoveryProducer"/>
@@ -7,8 +7,8 @@ import org.jetbrains.annotations.NotNull;
public final class JUnitExternalLibraryDescriptor extends ExternalLibraryDescriptor {
public static final ExternalLibraryDescriptor JUNIT3 = new JUnitExternalLibraryDescriptor("junit", "junit", "3", "3.8.2", "3.0");
public static final ExternalLibraryDescriptor JUNIT4 = new JUnitExternalLibraryDescriptor("junit", "junit", "4", "4.13.1", "4.0");
public static final ExternalLibraryDescriptor JUNIT5 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "5", "5.13.4", "5.0.0");
public static final ExternalLibraryDescriptor JUNIT6 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "6", "6.0.0-RC2", "6.0.0-RC2");
public static final ExternalLibraryDescriptor JUNIT5 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "5", "5.14.0", "5.0.0");
public static final ExternalLibraryDescriptor JUNIT6 = new JUnitExternalLibraryDescriptor("org.junit.jupiter", "junit-jupiter", "6", "6.0.0", "6.0.0");
private final String myVersion;
private JUnitExternalLibraryDescriptor(@NotNull String groupId,
@@ -1,33 +1,13 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.junit.codeInsight;
import com.intellij.codeInsight.daemon.quickFix.ExternalLibraryResolver;
import com.intellij.execution.junit.JUnitExternalLibraryDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ExternalLibraryDescriptor;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
public final class JUnit5ExternalLibraryResolver extends ExternalLibraryResolver {
private static final Set<String> JUNIT5_ANNOTATIONS = Set.of(
"Test", "Disabled", "TestFactory", "BeforeEach", "BeforeAll", "AfterEach", "AfterAll", "DisplayName", "Nested"
);
public final class JUnit5ExternalLibraryResolver extends JupiterExternalLibraryResolver {
@Override
public @Nullable ExternalClassResolveResult resolveClass(@NotNull String shortClassName, @NotNull ThreeState isAnnotation, @NotNull Module contextModule) {
if (isAnnotation == ThreeState.YES && JUNIT5_ANNOTATIONS.contains(shortClassName)) {
return new ExternalClassResolveResult("org.junit.jupiter.api." + shortClassName, JUnitExternalLibraryDescriptor.JUNIT5);
}
return null;
protected @NotNull ExternalLibraryDescriptor getDescriptor() {
return JUnitExternalLibraryDescriptor.JUNIT5;
}
@Override
public @Nullable ExternalLibraryDescriptor resolvePackage(@NotNull String packageName) {
if (packageName.equals("org.junit.jupiter") || packageName.equals("org.junit")) {
return JUnitExternalLibraryDescriptor.JUNIT5;
}
return null;
}
}
}
@@ -0,0 +1,13 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.junit.codeInsight;
import com.intellij.execution.junit.JUnitExternalLibraryDescriptor;
import com.intellij.openapi.roots.ExternalLibraryDescriptor;
import org.jetbrains.annotations.NotNull;
public final class JUnit6ExternalLibraryResolver extends JupiterExternalLibraryResolver {
@Override
protected @NotNull ExternalLibraryDescriptor getDescriptor() {
return JUnitExternalLibraryDescriptor.JUNIT6;
}
}
@@ -0,0 +1,34 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.execution.junit.codeInsight;
import com.intellij.codeInsight.daemon.quickFix.ExternalLibraryResolver;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ExternalLibraryDescriptor;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
abstract class JupiterExternalLibraryResolver extends ExternalLibraryResolver {
private static final Set<String> JUPITER_ANNOTATIONS = Set.of(
"Test", "Disabled", "TestFactory", "BeforeEach", "BeforeAll", "AfterEach", "AfterAll", "DisplayName", "Nested"
);
@Override
public @Nullable ExternalClassResolveResult resolveClass(@NotNull String shortClassName, @NotNull ThreeState isAnnotation, @NotNull Module contextModule) {
if (isAnnotation == ThreeState.YES && JUPITER_ANNOTATIONS.contains(shortClassName)) {
return new ExternalClassResolveResult("org.junit.jupiter.api." + shortClassName, getDescriptor());
}
return null;
}
protected abstract @NotNull ExternalLibraryDescriptor getDescriptor();
@Override
public @Nullable ExternalLibraryDescriptor resolvePackage(@NotNull String packageName) {
if (packageName.equals("org.junit.jupiter") || packageName.equals("org.junit")) {
return getDescriptor();
}
return null;
}
}
@@ -4,7 +4,10 @@ package com.intellij.junit6;
import com.intellij.codeInsight.TestFrameworks;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.configurations.JavaParameters;
import com.intellij.execution.junit.*;
import com.intellij.execution.junit.JUnit4Framework;
import com.intellij.execution.junit.JUnit6Framework;
import com.intellij.execution.junit.JUnitConfiguration;
import com.intellij.execution.junit.JUnitUtil;
import com.intellij.execution.junit2.info.MethodLocation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiMethod;
@@ -13,6 +16,8 @@ import one.util.streamex.StreamEx;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
@@ -185,4 +190,26 @@ public class JUnit6AcceptanceTest extends JUnit6CodeInsightTest {
PsiClass customEngineAnnotationOnSuper = myFixture.addClass("class MyCustomClass extends MyTests{}");
assertTrue(JUnitUtil.isTestClass(customEngineAnnotationOnSuper));
}
@Test
void junit6LibraryAdjustments() {
myFixture.configureByText("MyTest.java",
"class MyTest {@org.junit.jupiter.api.<error descr=\"Cannot resolve symbol 'BeforeEach'\">Before<caret>Each</error> void method() {}}");
myFixture.testHighlighting(false, false, false);
final Set<String> frameworks = myFixture.getAllQuickFixes().stream()
.map(action -> action.getText())
.filter(name -> name.startsWith("Add")).collect(Collectors.toSet());
assertAll("Detected frameworks: " + frameworks,
() -> assertTrue(frameworks.contains("Add 'JUnit6' to classpath")));
myFixture.configureByText("MyTest.java",
"class MyTest {@<error descr=\"Cannot resolve symbol 'DisplayName'\">DisplayName</error> void method() {}}");
myFixture.testHighlighting(false, false, false);
Set<String> displayNameFrameworks = myFixture.getAllQuickFixes().stream()
.map(action -> action.getText())
.filter(name -> name.startsWith("Add")).collect(Collectors.toSet());
assertAll("Detected frameworks: " + displayNameFrameworks,
() -> assertTrue(displayNameFrameworks.contains("Add 'JUnit6' to classpath")));
}
}