Why Can't I access src/test/resources in Junit test run with Maven?

I am having a problems running the following code:

configService.setMainConfig("src/test/resources/MainConfig.xml");

From within a Junit @Before method.

Is this the way Maven builds out its target folder?


Solution 1:

Access MainConfig.xml directly. The src/test/resources directory contents are placed in the root of your CLASSPATH.

More precisely: contents of src/test/resources are copied into target/test-classes, so if you have the following project structure:

.
└── src
    └── test
        ├── java
        │   └── foo
        │       └── C.java
        └── resources
            ├── a.xml
            └── foo
                └── b.xml

It will result with the following test CLASSPATH contents:

  • /foo/C.class
  • /a.xml
  • /foo/b.xml

To actually access the files from Java source, use getClass().getResource("/MainConfig.xml").getFile().

Solution 2:

I ran into the same problem today and I have found some solutions.

First, here is my file structure:

.
└── src
│   └── test
│       ├── java
│       │   └── mypackage
│       │       └── MyClassTest.java
│       └── resources
│           └── image.jpg
└── target
    └── test-classes
            ├── image.jpg
            └── mypackage
                └── MyClassTest.class  

What is not working: (Java 11 synthax)

var imgFile = new File("image.jpg"); // I was expecting that Junit could find the file.
var absPath = file.getAbsolutePath(); // /home/<user>/../<project-root>/image.jpg
var anyFileUnderThisPath = file.exists(); // false

What we can notice is that the absolute path does not point at all on my image! But if I had an image under at the project-root, then it would have worked.

Solution 1: Paths (introduced in Java 7)

var relPath = Paths.get("src", "test", "resources", "image.jpg"); // src/test/resources/image.jgp
var absPath = relPath.toFile().getAbsolutePath(); // /home/<user>/../<project-root>/src/test/resources/image.jpg
var anyFileUnderThisPath = new File(absPath).exists(); // true

As we can see, it points on the right file.

Solution 2: ClassLoader

var classLoader = getClass().getClassLoader();
var url = classLoader.getResource("image.jpg"); // file:/home/<user>/../<project-root>/target/test-classes/image.jpg
var file = new File(url.getFile()); // /home/<user>/../<project-root>/target/test-classes/image.jpg
var anyFileUnderThisPath = file.exists(); // true

Note that now the file is searched under the target directory! and it works.

Solution 3: File (Adaptation of the non-working example)

var absPath = new File("src/test/resources/image.jpg").getAbsolutePath();
var var anyFileUnderThisPath = new File(absPath).exists(); // true

Which works also after taking the absolute path and putting src/test/resources/ as prefix.

Summary

All three solutions works but having to put src/test/resources/ is, in my own opinion not elegant, and this is why I would prefer the 2nd solution (ClassLoader).

Sources:

  • Read file and resource in junit test
  • Java read a file from resources folder

Solution 3:

I guess setMainConfig expects the path of a resource, that it will load using the ClassLoader, and not a relative file path. It would help if you linked to the javadoc of this mysterious configService.setMainConfig method.

If my guess is correct, then the path should just be MainConfig.xml. Mave copies the contents of src/test/resources to the target/test-classes (IIRC) folder. And this test-classes folder is in the classpath of the unit tests.