Java 从JUnit获取资源流
我正在为需要在初始化期间加载配置文件的项目创建JUnit测试用例 此配置文件位于src/main/resources/config文件夹中的项目中,在构建期间,maven将其放入JAR中的/config文件夹中 初始化类使用以下语句从那里读取文件:Java 从JUnit获取资源流,java,junit,classloader,getresource,Java,Junit,Classloader,Getresource,我正在为需要在初始化期间加载配置文件的项目创建JUnit测试用例 此配置文件位于src/main/resources/config文件夹中的项目中,在构建期间,maven将其放入JAR中的/config文件夹中 初始化类使用以下语句从那里读取文件: ClassLoader classloader = this.getClass().getClassLoader(); BufferedReader xmlSource = new BufferedReader(new InputStreamRead
ClassLoader classloader = this.getClass().getClassLoader();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(classLoader.getResourceAsStream("/config/config.xml")));
我遇到的问题是,当我将这个jar部署并执行到应用服务器时,它会按预期工作,但是,每当我在Eclipse中的JUnit测试用例中运行它时,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
我知道类似的问题在StackOverflow中已经被问过很多次了,但是我找到的所有回答都是关于更改文件加载方式的,尽管更改代码可能是一种选择,我更愿意为文件找到正确的位置,这样我就不需要修改已经在生产环境中工作的内容
那么,我应该把这个文件放在哪里才能在JUnit测试中使用它呢
更新
我刚刚提出了解决方案,对代码做了一个小改动:
我没有使用类加载器获取资源,而是直接使用类:
Class clazz = this.getClass();
BufferedReader xmlSource = new BufferedReader(new InputStreamReader(clazz.getResourceAsStream("/config/config.xml")));
并且它成功地从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);
}
如果我调试它,我可以清楚地看到,这个getClassLoader0()返回的对象(id)与上一个调用this.getClass().getResourceAsStream()完全相同(我维护了它,只是为了比较值)
这是怎么回事
为什么直接调用方法不起作用,而在两者之间插入一个新的方法调用起作用
老实说,我真的很惊讶
顺便说一句,我使用的是JUnit4.10版。它可能以某种方式篡改了getClassLoader调用吗
非常感谢,
Carles我不确定这一点,但您可以尝试将资源文件夹放在src/main树中,而不是放在src/test树中。至少在某些配置中,eclipse将“资源”文件从src复制到类,而不是从测试复制到类。值得一试…回答你的问题 如果我调试它,我可以清楚地看到,这个getClassLoader0()返回的对象(id)与上一个调用this.getClass().getResourceAsStream()完全相同(我维护了它,只是为了比较值) 这是怎么回事 为什么直接调用方法不起作用,而在两者之间插入一个新的方法调用起作用 打电话和打电话的区别
this.getClass().getClassLoader().getResourceAsStream("/config/config.xml");
和呼唤
this.getClass().getResourceAsStream("/config/config.xml");
位于您在类中显示的确切来源中:
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);
}
但是问题不在于getClassLoader0()
返回的内容。在这两种情况下,它返回相同的内容。区别实际上在于resolveName(name)
。这是类
类中的私有方法
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;
}
私有字符串解析名称(字符串名称){
if(name==null){
返回名称;
}
如果(!name.startsWith(“/”){
c类=这类;
而(c.isArray()){
c=c.getComponentType();
}
字符串baseName=c.getName();
int index=baseName.lastIndexOf('.');
如果(索引!=-1){
name=baseName.substring(0,索引).replace('.','/'))
+“/”+姓名;
}
}否则{
name=name.substring(1);
}
返回名称;
}
因此,您可以看到,在实际调用类加载器的getResourceAsStream()
之前,它实际上从路径中删除了起始斜杠
一般来说,当它没有斜杠时,它会尝试获取与this
相关的资源,如果它在开始时有斜杠,则将其传递给类加载器
classLoader的getResourceAsStream()
方法实际上是用于相对路径的(否则您只需使用FileInputStream
)
所以当您使用this.getClass().getClassLoader().getResourceAsStream(“/config/config.xml”)代码>,实际上是在开始处用斜杠传递路径,但失败了。当您使用this.getClass().getResourceAsStream(“/config/config.xml”)
为您删除它真是太好了。类加载器中的getResourceAsStream
函数将不会删除搜索字符串前面的斜杠,因为搜索将相对于类路径进行。i、 e搜索用于加载类的搜索路径所在的资源
例如,假设您的类yourpackage/Test.class
,位于系统类加载器(即默认类加载器)加载的/a/b/c/d/yourpackage/Test.class
下,并且您的类路径必须指向/a/b/c/d
,才能加载该类。将在此路径上执行搜索
getResourceAsStream
类对象中的函数确实会删除搜索字符串前面的斜杠,因为搜索将相对于它所在的类进行。i、 e搜索从中加载类的资源
例如,如果从/a/b/c/d/yourpackage/Test.class
加载yourpackage/Test.class
,则资源路径将是/a/b/c/d/yourpackage/config/config.xml
您可以使用以下代码snipet来测试这一点,因为getResource
和getresourceastream
都使用相同的搜索算法
System.out.println(Test.class.getClassLoader().getResource("config/config.xml"));
System.out.println(Test.class.getResource("config/config.xml"));
src/test/resources/
是Eclipse中的源文件夹吗?@Sotirios