Monday, June 18, 2007

Proper way to access file resources in junit tests

As I was refactoring some JUnit tests recently I was reminded of an important fact on the proper way to read in a file.
In maven any file under /src/test/resources is automatically copied over to /target/test-classes. So for example lets say I need to read in a wsdl in my test. So I place the wsdl in the resources folder: /src/test/resources/test.wsdl. Now at first it might be tempting to reference the file with the following code:

File testWsdl = new File("/src/test/resources/test.wsdl");

and this will actually work on a windows machine; but what about linux, cygwin, or even solaris. Your next improvement might be to replace the '/' with File.separator:


File testWsdl = new File(File.separator + "src" + File.separator + "test"
    + File.separator + "resources" + File.separator + "test.wsdl");

This still isn't the best solution which is presented below:

URL url = this.getClass().getResource("/test.wsdl");
File testWsdl = new File(url.getFile());


Using the class's resource will locate the file in the test's classpath, which happens to be /target/test-classes. And this final solution will work on windows, linux, cygwin, and solaris.

14 comments:

CodeBeneath said...

Hammer, meet the head of the nail.

Carlus Henry said...

James,

I really appreciate you posting this. I have been scouring the net looking for the way to reference a resource through the maven build. It was working in Eclipse, but it did not work through the maven build.

Thanks for helping me solve this one.

jlorenzen said...

FYI,
To accomplish this in a Groovy Test that extends GroovyTestCase I had to replace the reference to 'this' to the current class.
Instead of:
URL url = this.getClass().getResource("/test.wsdl");

in groovy would be
def url = new DriverTest().getClass().getResource("/test.wsdl")

Where DriverTest is the actually test class.

David Brown said...

Hello James, when I googled this as the first entry on the first try to find a solution I thought: Wow! this can't be this easy! Alas, it does not work. I am very surprised because as you say a so-called: resources directory gets special treatment in Maven. And, sure-enough the so-called: test file is copied to test-classes. I have even tried to use new File("../../../../"+filename) since the test file is exactly four directory levels above the test class packaging. I have done something similar with a Maven resources directory for my war file resources using getResourceAsStream() which does work. Any ideas of how to debug this? Please advise, David.

I82Much said...

Thank you, this is perfect. I saw a similar article talking about using getResourceAsStream but I needed a path instead.

One note:

I had a lot of trouble getting this to work before I realized that the URL replaces spaces with %20; the File created from such a path (if it's local on your machine) will not work like that! So I ended up doing the following rather circuitous route:


URL url = this.getClass().getResource(CBT_COA1);
String pathWithoutPercents = url.getFile().replace("%20", " ");

File f = new File(pathWithoutPercents);

Paul Middelkoop said...

Spring has some handy utils so you don't have that spaces problem:

ResourceUtils.getFile(this.getClass().getResource("/filename.txt"))

Anonymous said...

Very usefuke, thanks!

Anonymous said...

Nice work - thanks a lot

Anonymous said...

Thank you

Dmitry Sobolev said...

Thank you very much!

Anonymous said...

T.Hanks, to favorites.

jlorenzen said...

Got this to work in groovy when I couldn't get anything else to work:
this.getClass().getResourceAsStream("/test.xml").text

Libor Jelinek said...

Thanks! It really helped me a lot!

Juan Carlos said...

Thank you!