来自JUnit的getResourceAsStream

Car*_*ala 13 java junit classloader getresource

我正在为一个需要在初始化期间加载配置文件的项目创建一个JUnit TestCase.

此配置文件位于src/main/resources/config文件夹中的项目内,并且在构建maven期间将其放入JAR内的/ config文件夹中.

初始化类,使用以下语句从那里读取文件:

ClassLoader classloader = this.getClass().getClassLoader();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream("/config/config.xml")));
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,当我将这个jar部署并执行到应用程序服务器时,它按预期工作,但是,每当我在Eclipse中的JUnit TestCase中运行它时,getResrouceAsStream方法返回null.

考虑到该类是my.package.MyClassTest.java,并且它位于src/test/java/my/package/MyClassTest.java中,我已经尝试将config.xml文件的副本放入以下文件夹中但没有成功:

- src/test/resources/config
- src/test/resources/my/package/config
- src/test/java/my/package/config
Run Code Online (Sandbox Code Playgroud)

我知道在StackOverflow中已经多次询问过类似的问题,但是我发现的所有响应都指的是改变文件的加载方式,虽然更改代码可能是一个选项,但我更愿意找到合适的地方.该文件所以我不需要修改已经在生产环境中工作的东西.

那么,我应该在哪里放置这个文件,以便能够在我的JUnit测试中使用它?

UPDATE

我只是通过对代码进行一些小改动来提出解决方案:我没有使用ClassLoader来获取资源,而是直接使用了类:

Class clazz = this.getClass();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(clazz.getResourceAsStream("/config/config.xml")));
Run Code Online (Sandbox Code Playgroud)

它从src/test/resources/config/config.xml成功读取文件.

但是,这里有一些非常奇怪的东西:Class.getResourceAsStream方法是:

public InputStream getResourceAsStream(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResourceAsStream(name);
    }
    return cl.getResourceAsStream(name);
}
Run Code Online (Sandbox Code Playgroud)

如果我调试它,我可以清楚地看到这个getClassLoader0()返回与前一个调用完全相同的对象(相同的id),this.getClass().getResourceAsStream()(我维护,只是为了比较值)! !

这里发生了什么?!

为什么在工作之间插入新方法调用时直接调用方法不起作用?

老实说,我对此非常惊讶.

顺便说一句,我使用的是JUnit 4.10版.可能以某种方式篡改getClassLoader调用吗?

非常感谢,

普约尔

Rea*_*tic 17

回答你的问题

如果我调试它,我可以清楚地看到这个getClassLoader0()返回与前一个调用完全相同的对象(相同的id),this.getClass().getResourceAsStream()(我维护,只是为了比较值)! !

这里发生了什么?!

为什么在工作之间插入新方法调用时直接调用方法不起作用?

呼唤之间的区别

this.getClass().getClassLoader().getResourceAsStream("/config/config.xml");
Run Code Online (Sandbox Code Playgroud)

并打电话

this.getClass().getResourceAsStream("/config/config.xml");
Run Code Online (Sandbox Code Playgroud)

位于您显示的确切来源Class:

public InputStream getResourceAsStream(String name) {
    name = resolveName(name);
    ClassLoader cl = getClassLoader0();
    if (cl==null) {
        // A system class.
        return ClassLoader.getSystemResourceAsStream(name);
    }
    return cl.getResourceAsStream(name);
}
Run Code Online (Sandbox Code Playgroud)

但问题不在于什么getClassLoader0()回报.它在两种情况下都返回相同的内容.实际上差别在于resolveName(name).这是Class该类中的私有方法.

private String resolveName(String name) {
    if (name == null) {
        return name;
    }
    if (!name.startsWith("/")) {
        Class<?> c = this;
        while (c.isArray()) {
            c = c.getComponentType();
        }
        String baseName = c.getName();
        int index = baseName.lastIndexOf('.');
        if (index != -1) {
            name = baseName.substring(0, index).replace('.', '/')
                +"/"+name;
        }
    } else {
        name = name.substring(1);
    }
    return name;
}
Run Code Online (Sandbox Code Playgroud)

所以你看,在实际调用classLoader之前getResourceAsStream(),它实际上从路径中删除了起始斜杠.

一般情况下,它会尝试获取相对于this没有斜杠的资源,如果它在开头有斜杠,则将其传递给classLoader.

classLoader的getResourceAsStream()方法实际上是用于相对路径(否则你只需要使用a FileInputStream).

所以当你使用时this.getClass().getClassLoader().getResourceAsStream("/config/config.xml");,你实际上是在路径中用斜杠传递它,但是失败了.当你使用this.getClass().getResourceAsStream("/config/config.xml");它时,它足够友好地为你删除它.