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

问题描述

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

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在实例化后使用,为了能够在Factory方法中测试故障转移逻辑,我需要在不同的类加载器中运行每个测试方法。

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?

编辑:这里是一些正在使用的Factory代码:

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测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-02 19:33