首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对不同的JUnit测试使用不同的类加载器?

对不同的JUnit测试使用不同的类加载器?
EN

Stack Overflow用户
提问于 2008-09-03 16:45:00
回答 5查看 24.6K关注 0票数 33

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

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

有没有办法用JUnit (或另一个单元测试包)做到这一点?

编辑:以下是一些正在使用的工厂代码:

代码语言:javascript
运行
复制
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;
}
EN

回答 5

Stack Overflow用户

发布于 2012-02-08 19:07:09

这个问题可能很老了,但因为这是我遇到这个问题时找到的最接近的答案,所以我想我应该描述一下我的解决方案。

使用JUnit 4的

拆分测试,这样每个类只有一个测试方法(这个解决方案只在类之间改变类加载器,而不是在方法之间,因为父运行器在每个类中收集所有方法一次)

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

创建如下所示的SeparateClassloaderTestRunner

代码语言:javascript
运行
复制
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);
        }
    }
}

请注意,我必须这样做才能测试在遗留框架中运行的代码,这是我无法更改的。如果可以选择,我会减少静态的使用和/或放置测试钩子,以允许系统重置。它可能不是很漂亮,但它允许我测试大量的代码,否则这些代码将是困难的。

此外,这个解决方案打破了任何其他依赖于类加载技巧的东西,比如Mockito。

票数 44
EN

Stack Overflow用户

发布于 2008-09-03 16:50:56

当我遇到这种情况时,我更喜欢使用有点像hack的东西。相反,我可能会公开一个受保护的方法,比如reinitialize(),然后从测试中调用它来有效地将工厂设置回其初始状态。这个方法只存在于测试用例中,我将其记录下来。

这是一个小技巧,但它比其他选择要容易得多,而且你不需要第三方库来做这件事(尽管如果你更喜欢更干净的解决方案,可能有一些第三方工具你可以使用)。

票数 3
EN

Stack Overflow用户

发布于 2008-09-03 17:10:20

您可以使用反射通过再次调用instantiateMyClass()来设置myClassImpl。看一下this answer,看看使用私有方法和变量的示例模式。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档