如何将文本文件资源读入 Java 单元测试?
Posted
技术标签:
【中文标题】如何将文本文件资源读入 Java 单元测试?【英文标题】:How to read a text-file resource into Java unit test? 【发布时间】:2011-04-22 22:13:40 【问题描述】:我有一个单元测试需要使用位于src/test/resources/abc.xml
的 XML 文件。将文件内容放入String
的最简单方法是什么?
【问题讨论】:
还有,***.com/questions/1656797/… @Nikita,尽管我的回答将投票结束,但这些问题没有提到getResourceAsStream()
,我认为这是解决 OP 问题的正确方法。
@kirk,getResourceAsStream 将文件缓存在类加载器中。这是不必要的。
@Thorbjørn,您的参考资料在哪里?无论如何,它确实是方便和便携,这实际上可能是必要的。
这个问题不应该被关闭。提供的“重复”不回答如何读取资源文件,而是一般的文件。问题是如何引用该资源文件
【参考方案1】:
感谢Apache Commons,终于找到了一个简洁的解决方案:
package com.example;
import org.apache.commons.io.IOUtils;
public class FooTest
@Test
public void shouldWork() throws Exception
String xml = IOUtils.toString(
this.getClass().getResourceAsStream("abc.xml"),
"UTF-8"
);
完美运行。文件src/test/resources/com/example/abc.xml
已加载(我正在使用 Maven)。
如果您将"abc.xml"
替换为"/foo/test.xml"
,则会加载此资源:src/test/resources/foo/test.xml
你也可以使用Cactoos:
package com.example;
import org.cactoos.io.ResourceOf;
import org.cactoos.io.TextOf;
public class FooTest
@Test
public void shouldWork() throws Exception
String xml = new TextOf(
new ResourceOf("/com/example/abc.xml") // absolute path always!
).asString();
【讨论】:
可以在没有外部库依赖的情况下简单地做到这一点。 @yegor256 因为它是一个单元测试,所以关闭资源是特别重要的。 “单元”测试应该是快速且自包含的,在测试运行期间保持资源开放,这意味着您的测试充其量是运行速度较慢,最坏的情况是以难以诊断的方式失败。 同样紧凑,但正确关闭了输入流:IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8")
.
嘿@yegor256,这不是IOUtils.toString
静态方法吗?根据你众所周知的static
不喜欢,你现在会如何解决它?
这仅适用于文件位于同一包中的情况。如果它们不在同一个包中怎么办【参考方案2】:
切入正题:
ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());
【讨论】:
在使用 junit 测试并希望通过将 xls 文件加载到 byte[] 表单来设置测试时为我工作。 OP 询问“将文件内容转换为字符串的最简单方法是什么?”这个答案如果直接回答就更好了。 getClass().getClassLoader().getResource("test.xml"); 文件 file = new File(getClass().getResource("/responses/example.json").getFile());似乎也可以正常工作,没有 getClassLoader()。 如果您的方法是静态的,这将不起作用。【参考方案3】:假定文件中使用 UTF8 编码 - 如果不是,只需省略 "UTF8" 参数 & 将使用 每种情况下底层操作系统的默认字符集。
JSE 6 中的快捷方式 - 简单且无第三方库!
import java.io.File;
public class FooTest
@Test public void readXMLToString() throws Exception
java.net.URL url = MyClass.class.getResource("test/resources/abc.xml");
//Z means: "The end of the input but for the final terminator, if any"
String xml = new java.util.Scanner(new File(url.toURI()),"UTF8").useDelimiter("\\Z").next();
JSE 7 中的快捷方式
public class FooTest
@Test public void readXMLToString() throws Exception
java.net.URL url = MyClass.class.getResource("test/resources/abc.xml");
java.nio.file.Path resPath = java.nio.file.Paths.get(url.toURI());
String xml = new String(java.nio.file.Files.readAllBytes(resPath), "UTF8");
Java 9 以来的快捷方式
new String(getClass().getClassLoader().getResourceAsStream(resourceName).readAllBytes());
不过,它们都不适用于巨大的文件。
【讨论】:
第二个例子不起作用,readAllBytes 似乎不接受 URL...我让它工作的最接近的是String xml = new String(java.nio.file.Files.readAllBytes(Paths.get(url.toURI())), "UTF8");
它确实有效 - 需要一个 Path 类型的参数。这就是为什么我称它为 resPath。 :)
上面将文件内容直接读入内存中的字符串。因此,例如,如果您有 4GB 的内存,那么介于 1-4GB 之间的文件可能会被归类为“巨大”,因为它会消耗非常大比例的内存资源(页面交换到磁盘,除此之外)。对于大文件,最好流式传输 - 分块读取,而不是一次全部读取。
java7版本完美,提示:使用StandardCharsets.UTF_8避免unsupportedEncodingException
你能解释一下为什么你使用 MyClass 而不是 FoTest 以及你什么时候想使用哪个类?【参考方案4】:
首先确保将abc.xml
复制到您的输出目录。那么你应该使用getResourceAsStream()
:
InputStream inputStream =
Thread.currentThread().getContextClassLoader().getResourceAsStream("test/resources/abc.xml");
一旦你有了 InputStream,你只需要把它转换成一个字符串。此资源详细说明:http://www.kodejava.org/examples/266.html。但是,我将摘录相关代码:
public String convertStreamToString(InputStream is) throws IOException
if (is != null)
Writer writer = new StringWriter();
char[] buffer = new char[1024];
try
Reader reader = new BufferedReader(
new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1)
writer.write(buffer, 0, n);
finally
is.close();
return writer.toString();
else
return "";
【讨论】:
什么是your output directory
?
@Vincenzo,通常是“类”,尽管可能是“bin”。即无论您将课程编译到哪里。大多数 IDE 已经将 xml 文件等资源文件复制到该目录,因此您可能应该快速查看它是否已经存在。
在您的情况下看起来代码太多。我最好使用一些apache.commons.io.*
类来读取文件,以及java.lang.Class.getResource()
。你怎么看?
一个很好的测试方法是,如果你将测试用例写在一个带有 testKey = value 的“.properties”文件中,然后你可以直接加载 InputStream。示例:属性 properties = new Properties();属性.load(inputStream); String testCase = properties.getProperty("testKey");
如何将abc.xml
复制到输出目录? @KirkWoll【参考方案5】:
使用谷歌番石榴:
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
public String readResource(final String fileName, Charset charset) throws Exception
try
return Resources.toString(Resources.getResource(fileName), charset);
catch (IOException e)
throw new IllegalArgumentException(e);
例子:
String fixture = this.readResource("filename.txt", Charsets.UTF_8)
【讨论】:
【参考方案6】:你可以试试:
String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml")).replace("\n","");
【讨论】:
你为什么要剥离新行? @zudduz 对不起,我不记得了,这是 2 年前的事了 IOUtils.toString toString(stream) 也被弃用了。需要在 IOUtils.toString 中传递一个 Charsets toString(stream, Charsets.UTF_8) (import com.google.common.base.Charsets;) 其实为了避免弃用,应该是: String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml"), StandardCharsets.UTF_8).replace("\n" ,"");【参考方案7】:这是我用来获取带有文本的文本文件的内容。我使用了 commons 的 IOUtils 和 guava 的 Resources。
public static String getString(String path) throws IOException
try (InputStream stream = Resources.getResource(path).openStream())
return IOUtils.toString(stream);
【讨论】:
【参考方案8】:您可以使用 Junit Rule 为您的测试创建这个临时文件夹:
@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
File file = temporaryFolder.newFile(".src/test/resources/abc.xml");
【讨论】:
【参考方案9】:好的,对于JAVA 8,经过大量调试 我发现两者之间存在差异
URL tenantPathURI = getClass().getResource("/test_directory/test_file.zip");
和
URL tenantPathURI = getClass().getResource("test_directory/test_file.zip");
是的,路径开头的/
没有它我得到null
!
而test_directory
位于test
目录下。
【讨论】:
以上是关于如何将文本文件资源读入 Java 单元测试?的主要内容,如果未能解决你的问题,请参考以下文章