ChatGPT解决这个技术问题 Extra ChatGPT

How to read a text-file resource into Java unit test?

I have a unit test that needs to work with XML file located in src/test/resources/abc.xml. What is the easiest way just to get the content of the file into String?

@Nikita, was going to vote to close despite my answer, but those questions don't mention getResourceAsStream() which I believe is the right approach for the OP's question.
@kirk, getResourceAsStream caches the file in the classloader. That is unnecessary.
@Thorbjørn, where is your reference for that? In any case, it certainly is convenient and portable which may in fact be necessary.
This question shouldn't be closed. The "duplicates" provided don't answer how to read a resource file, but files in general. The problem is how to reference that resource file

y
yegor256

Finally I found a neat solution, thanks to 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"
    );
  }
}

Works perfectly. File src/test/resources/com/example/abc.xml is loaded (I'm using Maven).

If you replace "abc.xml" with, say, "/foo/test.xml", this resource will be loaded: src/test/resources/foo/test.xml

You can also use 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();
  }
}

Can do this as simply without external library dependency.
@yegor256 since it's a unit test closing resources is particularly important. "Unit" tests should be fast and self contained, leaving resources open, potentially for the duration of the test run, means at best your tests run slower, and at worst fail in difficult-to-diagnose ways.
Just as compact, but with proper closing of the input stream: IOUtils.toString(this.getClass().getResource("foo.xml"), "UTF-8").
Hey @yegor256, isn't IOUtils.toString static method? How would you solve it now, according to your well known static dislike?
This only works if the file is located in the same package. What if they are not in the same package
a
akash

Right to the point :

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("file/test.xml").getFile());

Works for me when using junit test and want to setup test by loading xls file into byte[] form.
OP asks "What is the easiest way just to get the content of the file into String?" This answer would be even better if it directly answered that.
getClass().getClassLoader().getResource("test.xml");
File file = new File(getClass().getResource("/responses/example.json").getFile()); Seems to work just fine too, without getClassLoader().
This won't work if your method is static.
G
GabrielBB

Assume UTF8 encoding in file - if not, just leave out the "UTF8" argument & will use the default charset for the underlying operating system in each case.

Quick way in JSE 6 - Simple & no 3rd party library!

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();
  }
}

Quick way in 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"); 
  }

Quick way since Java 9

new String(getClass().getClassLoader().getResourceAsStream(resourceName).readAllBytes());

Neither intended for enormous files though.


the 2nd example doesn't work, readAllBytes doesn't seem to accept URL... the closest I got to make it work is String xml = new String(java.nio.file.Files.readAllBytes(Paths.get(url.toURI())), "UTF8");
It does work - needs an argument of type Path. That's why I called it resPath. :)
The above reads the file contents directly into a string in memory. So, for example, if you have 4GB of memory, then a file of somewhere between 1-4GB probably classifies as "enormous" because it will consume a very significant proportation of memory resources (page swapping to disk, aside). For large files, better to stream - read in chunks, not all at once.
java7 version is perfect, tip: use StandardCharsets.UTF_8 to avoid the unsupportedEncodingException
Can you explain why you're using MyClass rather than for example FoTest and when you want to use which class?
K
Kirk Woll

First make sure that abc.xml is being copied to your output directory. Then you should use getResourceAsStream():

InputStream inputStream = 
    Thread.currentThread().getContextClassLoader().getResourceAsStream("test/resources/abc.xml");

Once you have the InputStream, you just need to convert it into a string. This resource spells it out: http://www.kodejava.org/examples/266.html. However, I'll excerpt the relevent code:

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 "";
    }
}

What is your output directory?
@Vincenzo, usually "classes" though perhaps "bin". i.e. wherever you are compiling your classes to. Most IDEs already copy resource files such as xml files to that directory so you should probably take a quick peak and see if it's already there.
Looks like too much code in your case. I would better use some apache.commons.io.* class for file reading, and java.lang.Class.getResource(). What do you think?
A nice way to test it would be if you write the test cases in a ".properties" file with testKey = value and then you can load the InputStream directly. Example: Properties properties = new Properties(); properties.load(inputStream); String testCase = properties.getProperty("testKey");
How to make that abc.xml be copied to output directory? @KirkWoll
D
Datageek

With the use of Google Guava:

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);
        }
}

Example:

String fixture = this.readResource("filename.txt", Charsets.UTF_8)

G
Guido Celada

You can try doing:

String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml")).replace("\n","");

Why are you stripping new lines?
@zudduz i'm sorry i don't remember, this was 2 years ago
IOUtils.toString toString(stream) is also deprecated. A Charsets needed to be passed in IOUtils.toString toString(stream, Charsets.UTF_8) (import com.google.common.base.Charsets;)
Actually to avoid deprecation, it should be : String myResource = IOUtils.toString(this.getClass().getResourceAsStream("yourfile.xml"), StandardCharsets.UTF_8).replace("\n","");
i
ikryvorotenko

Here's what i used to get the text files with text. I used commons' IOUtils and guava's Resources.

public static String getString(String path) throws IOException {
    try (InputStream stream = Resources.getResource(path).openStream()) {
        return IOUtils.toString(stream);
    }
}

A
Ahmed Ashour

You can use a Junit Rule to create this temporary folder for your test:

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
File file = temporaryFolder.newFile(".src/test/resources/abc.xml");

K
KhogaEslam

OK, for JAVA 8, after a lot of debugging I found that there's a difference between

URL tenantPathURI = getClass().getResource("/test_directory/test_file.zip");

and

URL tenantPathURI = getClass().getResource("test_directory/test_file.zip");

Yes, the / at the beginning of the path without it I was getting null!

and the test_directory is under the test directory.


d
djangofan

Using Commons.IO, this method works from EITHER a instance method or a static method:

public static String loadTestFile(String fileName) {
    File file = FileUtils.getFile("src", "test", "resources", fileName);
    try {
        return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
    } catch (IOException e) {
        log.error("Error loading test file: " + fileName, e);
        return StringUtils.EMPTY;
    }
}