如何将文本文件资源读入 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 单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

java中如何实现删除文本文档里面的指定字符

文本文档格式下,如何把一列数据改为连续的行数据?

VB中读入文件,如何获得文本的行数

如何在 Python 中对大文本文件流进行过滤和排序

查找哈希集中每个单词在文本文档中出现的次数

求Python程序,将固定文本文件中的文本按某字符串分开,输出几个新的文本文件