ExcludeClassJunitRunner.java

package top.infra.test.classloader.exclude;

import lombok.SneakyThrows;

import org.junit.runner.Runner;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;

import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import top.infra.test.classloader.ClassLoaderChangerRunner;
import top.infra.test.classloader.ClassUtils;

public class ExcludeClassJunitRunner extends Suite {

    private static URLClassLoader currentClassLoader;
    private static ExcludeClassesClassLoader customClassLoader;

    static {
        currentClassLoader = (URLClassLoader) Thread.currentThread().getContextClassLoader();
        customClassLoader = new ExcludeClassesClassLoader(
            currentClassLoader,
            currentClassLoader.getURLs(),
            null
        );
    }

    public ExcludeClassJunitRunner(final Class<?> klass) throws InitializationError {
        super(
            ClassUtils.loadFromCustomClassloader(customClassLoader, klass),
            buildRunners(ClassUtils.loadFromCustomClassloader(customClassLoader, klass)));
    }

    // Runs junit tests in a separate thread using the custom class loader
//    @Override
//    public void run(final org.junit.runner.notification.RunNotifier notifier) {
//        final Runnable runnable = () -> {
//            super.run(notifier);
//        };
//        final Thread thread = new Thread(runnable);
//        thread.setContextClassLoader(customClassLoader);
//        thread.start();
//        try {
//            thread.join();
//        } catch (final InterruptedException ex) {
//            Thread.currentThread().interrupt();
//        }
//    }

    @SneakyThrows
    private static List<Runner> buildRunners(final Class<?> klass) {
        final ExcludeClasses excludeClasses = klass.getAnnotation(ExcludeClasses.class);
        if (excludeClasses == null) throw new IllegalArgumentException("Class " + klass + " is missing ExcludeClasses annotation");

        customClassLoader.setExcludes(Arrays.asList(excludeClasses.excludesClasses()));

        final Class<?> testClass = customClassLoader.loadClass(klass.getName());

        final Class<?> runnerClass = excludeClasses.runner();
        final BlockJUnit4ClassRunner junit4Runner =
            (BlockJUnit4ClassRunner) runnerClass.getConstructor(Class.class).newInstance(testClass);

        final List<Runner> runners = new ArrayList<>();
        runners.add(new ClassLoaderChangerRunner(currentClassLoader, customClassLoader, junit4Runner));
        return runners;
    }
}