Skip to content

Commit

Permalink
feat: Add @nested support for JUnit 5 (#716)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdneo authored May 31, 2019
1 parent c6fffeb commit daad335
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@

public class JUnit4TestSearcher extends BaseFrameworkSearcher {

public static final String RUN_WITH = "org.junit.runner.RunWith";

public JUnit4TestSearcher() {
super();
this.testMethodAnnotations = new String[] { "org.junit.Test", "org.junit.experimental.theories.Theory" };
this.testClassAnnotations = new String[] { "org.junit.runner.RunWith" };
this.testClassAnnotations = new String[] { RUN_WITH };
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,16 @@

public class JUnit5TestSearcher extends BaseFrameworkSearcher {

public static final String NESTED = "org.junit.jupiter.api.Nested";

protected static final String DISPLAY_NAME_ANNOTATION_JUNIT5 = "org.junit.jupiter.api.DisplayName";

public JUnit5TestSearcher() {
super();
this.testMethodAnnotations = new String[] { "org.junit.jupiter.api.Test",
"org.junit.jupiter.params.ParameterizedTest", "org.junit.jupiter.api.RepeatedTest",
"org.junit.jupiter.api.TestFactory" };
this.testClassAnnotations = new String[] {};
this.testClassAnnotations = new String[] { NESTED };
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
import com.google.gson.Gson;
import com.microsoft.java.test.plugin.model.SearchTestItemParams;
import com.microsoft.java.test.plugin.model.TestItem;
import com.microsoft.java.test.plugin.model.TestKind;
import com.microsoft.java.test.plugin.model.TestLevel;
import com.microsoft.java.test.plugin.searcher.JUnit4TestSearcher;
import com.microsoft.java.test.plugin.searcher.JUnit5TestSearcher;

import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.ResourcesPlugin;
Expand All @@ -24,14 +27,14 @@
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.search.IJavaSearchConstants;
Expand Down Expand Up @@ -107,11 +110,10 @@ public static List<TestItem> searchCodeLens(List<Object> arguments, IProgressMon
resultList.add(parent);
continue;
}
// Check if the class can still run tests even no method is annotated.
// For example, annotated with @RunWith
final TestItem runableClass = TestFrameworkUtils.resolveTestItemForClass(type);
if (runableClass != null) {
resultList.add(runableClass);
// Class annotated by @RunWith should be considered as a Suite even it has no test method children
if (TestFrameworkUtils.hasAnnotation(type, JUnit4TestSearcher.RUN_WITH)) {
resultList.add(TestItemUtils.constructTestItem(type, TestItemUtils.getTestLevelForIType(type),
TestKind.JUnit));
}
}

Expand Down Expand Up @@ -430,21 +432,27 @@ private static List<TestItem> searchTestMethodsOfType(IType type) throws JavaMod
}

private static boolean isTestableClass(IType type) throws JavaModelException {
int flags = type.getFlags();
final int flags = type.getFlags();
if (Flags.isInterface(flags) || Flags.isAbstract(flags)) {
return false;
}
IJavaElement parent = type.getParent();
while (true) {
if (parent instanceof ICompilationUnit || parent instanceof IClassFile) {
return true;
}
if (!(parent instanceof IType) || !Flags.isStatic(flags) || !Flags.isPublic(flags)) {
return false;
}
flags = ((IType) parent).getFlags();
parent = parent.getParent();

final IJavaElement parent = type.getParent();

if (parent instanceof ITypeRoot) {
return true;
}

if (!(parent instanceof IType)) {
return false;
}

if (TestFrameworkUtils.hasAnnotation(type, JUnit5TestSearcher.NESTED) ||
(Flags.isStatic(flags) && Flags.isPublic(flags))) {
return true;
}

return false;
}

private static boolean isJavaElementExist(IJavaElement element) {
Expand Down
34 changes: 25 additions & 9 deletions src/runners/junit5Runner/JUnit5RunnerResultAnalyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,33 @@ export class JUnit5RunnerResultAnalyzer extends BaseRunnerResultAnalyzer {
if (!id) {
return id;
}
const regex: RegExp = /\[class:(.*?)\]\/\[(?:method|test-template|test-factory):(.*)\]/gm;
const match: RegExpExecArray | null = regex.exec(id);
if (match && match.length === 3) {
let methodName: string = match[2];
const index: number = methodName.indexOf('(');
if (index >= 0) {
methodName = methodName.substring(0, index);
let res: string = '';
const regex: RegExp = /\[(.*?):(.*?)\]/g;
while (true) {
const execResult: RegExpExecArray | null = regex.exec(id);
if (!execResult || execResult.length < 3) {
break;
}
switch (execResult[1]) {
case 'class':
res += execResult[2];
break;
case 'nested-class':
res += `$${execResult[2]}`;
break;
case 'method':
case 'test-template':
case 'test-factory':
let methodName: string = execResult[2];
const index: number = methodName.indexOf('(');
if (index >= 0) {
methodName = methodName.substring(0, index);
}
res += `#${methodName}`;
break;
}
return `${match[1]}#${methodName}`;
}
return '';
return res;
}

private parseTestStatus(status: JUnit5TestStatus): TestStatus {
Expand Down

0 comments on commit daad335

Please sign in to comment.