SeparateClassloaderTestRunner

SeparateClassloaderTestRunner

本文介绍了对不同的 JUnit 测试使用不同的类加载器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个单例/工厂对象,我想为其编写 JUnit 测试.工厂方法根据类路径上的属性文件中的类名决定要实例化哪个实现类.如果没有找到属性文件,或者属性文件不包含类名键,那么该类将实例化一个默认的实现类.

I have a Singleton/Factory object that I'd like to write a JUnit test for. The Factory method decides which implementing class to instantiate based upon a classname in a properties file on the classpath. If no properties file is found, or the properties file does not contain the classname key, then the class will instantiate a default implementing class.

由于工厂保留了 Singleton 的静态实例以在实例化后使用,为了能够在工厂方法中测试故障转移"逻辑,我需要在不同的类加载器中运行每个测试方法.

Since the factory keeps a static instance of the Singleton to use once it has been instantiated, to be able to test the "failover" logic in the Factory method I would need to run each test method in a different classloader.

JUnit(或其他单元测试包)有没有办法做到这一点?

Is there any way with JUnit (or with another unit testing package) to do this?

这里是一些正在使用的工厂代码:

edit: here is some of the Factory code that is in use:

private static MyClass myClassImpl = instantiateMyClass();

private static MyClass instantiateMyClass() {
    MyClass newMyClass = null;
    String className = null;

    try {
        Properties props = getProperties();
        className = props.getProperty(PROPERTY_CLASSNAME_KEY);

        if (className == null) {
            log.warn("instantiateMyClass: Property [" + PROPERTY_CLASSNAME_KEY
                    + "] not found in properties, using default MyClass class [" + DEFAULT_CLASSNAME + "]");
            className = DEFAULT_CLASSNAME;
        }

        Class MyClassClass = Class.forName(className);
        Object MyClassObj = MyClassClass.newInstance();
        if (MyClassObj instanceof MyClass) {
            newMyClass = (MyClass) MyClassObj;
        }
    }
    catch (...) {
        ...
    }

    return newMyClass;
}

private static Properties getProperties() throws IOException {

    Properties props = new Properties();

    InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(PROPERTIES_FILENAME);

    if (stream != null) {
        props.load(stream);
    }
    else {
        log.error("getProperties: could not load properties file [" + PROPERTIES_FILENAME + "] from classpath, file not found");
    }

    return props;
}

推荐答案

这个问题可能很老了,但由于这是我遇到这个问题时找到的最接近的答案,我想我会描述我的解决方案.

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.

使用 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)

@RunWith(SeparateClassloaderTestRunner.class) 注释添加到您的测试类中.

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

创建 SeparateClassloaderTestRunner 如下所示:

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.

此外,该解决方案也打破了依赖类加载技巧(例如 Mockito)的任何其他内容.

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

这篇关于对不同的 JUnit 测试使用不同的类加载器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-11 07:23