Skip to content

Can't select JUnit 4 classes via DiscoverySelectors.selectClass from inside shadow jar #4872

@fapdash

Description

@fapdash

I've uploaded a minimal reproduction to this repository: https://github.com/fapdash/junit-classselection-reproduction.

I'll reproduce the main method here:

package reproduction;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;

import org.junit.platform.engine.discovery.DiscoverySelectors;
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
import org.junit.platform.launcher.core.LauncherFactory;

public class Main {
	public static void main(String[] args) throws IOException {
		var className = "ExampleJUnit4Test";
		compileAndSelect(className);
		className = "ExampleJUnit5Test";
		compileAndSelect(className);
	}

	private static void compileAndSelect(String className) throws IOException {
		System.out.format("Testing class: %s\n", className);
		var compiler = ToolProvider.getSystemJavaCompiler();
		var diagnosticCollector = new DiagnosticCollector<>();
		StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnosticCollector, null, null);

		Path tempDirectory = Files.createTempDirectory(String.format("junit-reproduction-"));
		System.out.format("Compiling to %s\n", tempDirectory);
		fileManager.setLocation(StandardLocation.CLASS_OUTPUT, List.of(tempDirectory.toFile()));

		Iterable<? extends JavaFileObject> sources = fileManager
				.getJavaFileObjectsFromPaths(List.of(Path.of(className + ".java")));
		var task = compiler.getTask(null, fileManager, diagnosticCollector, null, null, sources);
		if (!task.call()) {
			System.out.println("Failed compilation!");
			return;
		}
		ClassLoader classLoader = fileManager.getClassLoader(StandardLocation.CLASS_OUTPUT);
		Iterable<? extends Path> classpathRootsIterable = fileManager.getLocationAsPaths(StandardLocation.CLASS_OUTPUT);
		Set<Path> classpathRoots = new HashSet<>();
		classpathRootsIterable.forEach(classpathRoots::add);

		var originalClassLoader = Thread.currentThread().getContextClassLoader();
		Thread.currentThread().setContextClassLoader(classLoader);
		var request = LauncherDiscoveryRequestBuilder.request()
				.selectors(DiscoverySelectors.selectClass(classLoader, className)).build();
		var launcher = LauncherFactory.create();
		var testPlan = launcher.discover(request);

		System.out.format("TestPlan contains tests: %s\n", testPlan.containsTests());

		Thread.currentThread().setContextClassLoader(originalClassLoader);
	}
}

When I run the example from inside of Eclipse I get the expected output, but when I run the example via the shadow jar JUnit doesn't select the JUnit 4 test class.

JUnit definitely finds the class, otherwise there would be a PreconditionViolationException, caused by a ClassNotFoundException. But for some reason JUnit doesn't select the class as a test class.

In the example repo I've used JUnit version 6.0.0-RC2, but I observe the same behavior with 5.13.4.

Steps to reproduce

Compile the project to a shadow jar and then run the example:

./gradlew clean build
java -jar build/libs/junit-classselection-reproduction-1.0-SNAPSHOT-all.jar 

Expected output would be

Testing class: ExampleJUnit4Test
Compiling to /tmp/junit-reproduction-abc
TestPlan contains tests: true
Testing class: ExampleJUnit5Test
Compiling to /tmp/junit-reproduction-xyz
TestPlan contains tests: true

Actual output:

Testing class: ExampleJUnit4Test
Compiling to /tmp/junit-reproduction-asd
TestPlan contains tests: false
Testing class: ExampleJUnit5Test
Compiling to /tmp/junit-reproduction-fgh
TestPlan contains tests: true

Context

  • Used versions (Jupiter/Vintage/Platform): Vintage
  • Build Tool/IDE: Gradle / Eclipse

I hope my reproduction is useful.
Let me know if you need any additional information!

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions