Using different classloaders for different JUnit tests?

This question might be old but since this was the nearest answer I found when I had this problem I though I’d describe my solution.

Using JUnit 4

Split your tests up so that there is one test method per class (this solution only changes classloaders between classes, not between methods as the parent runner gathers all the methods once per class)

Add the @RunWith(SeparateClassloaderTestRunner.class) annotation to your test classes.

Create the SeparateClassloaderTestRunner to look like this:

public class SeparateClassloaderTestRunner extends BlockJUnit4ClassRunner {

    public SeparateClassloaderTestRunner(Class<?> clazz) throws InitializationError {
        super(getFromTestClassloader(clazz));
    }

    private static Class<?> getFromTestClassloader(Class<?> clazz) throws InitializationError {
        try {
            ClassLoader testClassLoader = new TestClassLoader();
            return Class.forName(clazz.getName(), true, testClassLoader);
        } catch (ClassNotFoundException e) {
            throw new InitializationError(e);
        }
    }

    public static class TestClassLoader extends URLClassLoader {
        public TestClassLoader() {
            super(((URLClassLoader)getSystemClassLoader()).getURLs());
        }

        @Override
        public Class<?> loadClass(String name) throws ClassNotFoundException {
            if (name.startsWith("org.mypackages.")) {
                return super.findClass(name);
            }
            return super.loadClass(name);
        }
    }
}

Note I had to do this to test code running in a legacy framework which I couldn’t change. Given the choice I’d reduce the use of statics and/or put test hooks in to allow the system to be reset. It may not be pretty but it allows me to test an awful lot of code that would be difficult otherwise.

Also this solution breaks anything else that relies on classloading tricks such as Mockito.

Leave a Comment