How to get the path of src/test/resources directory in JUnit?
Asked Answered
F

17

337

I know I can load a file from src/test/resources with:

getClass().getResource("somefile").getFile()

But how can I get the full path to the src/test/resources directory, i.e. I don't want to load a file, I just want to know the path of the directory?

Floriculture answered 23/2, 2015 at 12:18 Comment(8)
Out of curiosity: why do you want to know?Spectrohelioscope
@Spectrohelioscope need to pass it to object under test, which uses it to load a fileFloriculture
@Spectrohelioscope I had a similar case for JBoss -- get deployment (war file) name of application to read configuration from /etc/mycompany/deployment_name/config (we have a lot of instances of same application deployed at same time).Yonah
Direct file access to your resource directory is a bad idea. Refactor your code to operate on a steam, or have your test create a copy in a TemporaryFolder first.Ri
Unfortunately, there are many libraries which accept only File objects (or Hadoop Path objects), not streams. While one could simply copy the test data to a temp file, then use that, it would be easier to know the path. Recognizing, of course, that anything built into a jar would defeat this.Darleen
@OliverCharlesworth I agree about temp folders and use org.junit.rules.TemporaryFolder all the time... but... to copy from test/resources you need to know, er, its path!Rico
@mikerodent - what I think meant was: read the resource via an inputstream, and then write it to a temporary file.Ri
There are three variants of solution, depending on the situation: https://mcmap.net/q/100462/-how-to-get-absolute-path-to-file-in-resources-folder-of-your-projectLeija
R
244

Try working with the ClassLoader class:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("somefile").getFile());
System.out.println(file.getAbsolutePath());

A ClassLoader is responsible for loading in classes. Every class has a reference to a ClassLoader. This code returns a File from the resource directory. Calling getAbsolutePath() on it returns its absolute Path.

Javadoc for ClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html

Rolfston answered 23/2, 2015 at 12:50 Comment(6)
This isn't necessarily a good idea. If the resource is in a Jar, this will lead to sad times.Ri
@OliverCharlesworth So, what can be done in case of jar?Kellam
@AnmolSinghJaggi - See my comment below the original question :)Ri
maven build fails when I use this solutionBenevolent
It will be with filename tooRidinger
is there a way to do this using the new Files API?Jodoin
R
370

You don't need to mess with class loaders. In fact it's a bad habit to get into because class loader resources are not java.io.File objects when they are in a jar archive.

Maven automatically sets the current working directory before running tests, so you can just use:

    File resourcesDirectory = new File("src/test/resources");

resourcesDirectory.getAbsolutePath() will return the correct value if that is what you really need.

I recommend creating a src/test/data directory if you want your tests to access data via the file system. This makes it clear what you're doing.

Rank answered 23/2, 2015 at 13:5 Comment(16)
new File("src/test/resources/fileXYZ"); will not work. Neither from Eclipse nor from Maven if you simply put that into a JUnit test.Isiah
It works just fine from Maven. In eclipse you will need to set the current working directory in the test runner, but command line maven does this for you.Rank
I don't think so. And why would you do that if you can do simply a "new File(getClass().getClassLoader().getResource("fileNameXYZ.xml")" without any need to set up anything. Neither in Eclipse nor in Maven.Isiah
Rather, why wouldn't you follow the standards of your build utility? Especially when it simplifies your code. Using IntelliJ or Maven, there's no need to set working directory. This is obviously the simplest solution, with Eclipse being a pain as always.Lophophore
For IntelliJ 2014 version , I had to still change the working directory in the Run/Debug configurations of the test method/class, as @Steve C mentioned.Malena
@JamesWatkins what I need to do to setup correctly? There are some projects that the root path could be different. As an example, I worked in a project that this code will return different results if you start the test (TestNG) from Intellij IDEA or start from Maven. In the first one it shows the resources from root project and in the second it shows the resources from the actual maven module. The same problem occur with a new File().Celia
Maven automatically sets the current working directory sets to what?Nettle
@KorayTugay, it sets it to the directory containing the pom.xml file for the module currently being built.Rank
Had the same issue, can anybody tell me how to access the file from "src/main/resource" path instead of "src/test" path as for test cases it is taking by default path as "src/test"?Pteridology
@Jitendra, do you want the file or the resource? Are you trying to access it from a unit test or at application runtime?Rank
@Steve C, I'm trying to access the file inside src/main/resource/file from a unit test.Pteridology
@Jitendra, if you want to read src/main/resources/data.txt from a unit test you can just use File dataFile = new File("src/main/resources/data.txt");Rank
@Steve C, I have already tried this but it's not working because when I checked, it's absolute path became src/test/src/main/resources/data.txt.Pteridology
Are you running this test from an IDE? If so this is happening to you because you have your launch configuration set up with the working directory pointing at src/test.Rank
This works fine with Android Gradle plugin 3.2.0 to 3.5.3Triphthong
I think the premise behind this answer is incorrect: it's a bad habit to get into because class loader resources are not java.io.File objects when they are in a jar archive. You still cannot use java.io.File objects to read from a jar. I don't like this answer because it relies on having to know how your source is laid out: src/test/resources etc. Using a classloader seems cleaner, because you are only concerned with the path to the file from some point in the classpath.. if you are looking for a file in a jar you still use class loaders: getClass().getResourceAsStream("/file.txt")Tetrabranchiate
R
244

Try working with the ClassLoader class:

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("somefile").getFile());
System.out.println(file.getAbsolutePath());

A ClassLoader is responsible for loading in classes. Every class has a reference to a ClassLoader. This code returns a File from the resource directory. Calling getAbsolutePath() on it returns its absolute Path.

Javadoc for ClassLoader: http://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html

Rolfston answered 23/2, 2015 at 12:50 Comment(6)
This isn't necessarily a good idea. If the resource is in a Jar, this will lead to sad times.Ri
@OliverCharlesworth So, what can be done in case of jar?Kellam
@AnmolSinghJaggi - See my comment below the original question :)Ri
maven build fails when I use this solutionBenevolent
It will be with filename tooRidinger
is there a way to do this using the new Files API?Jodoin
C
92

I would simply use Path from Java 7

Path resourceDirectory = Paths.get("src","test","resources");

Neat and clean!

Calla answered 21/2, 2017 at 18:53 Comment(8)
Will this exact same code work on Windows? The JavaDoc for Paths.get(...) suggests (to me anyway) that it it won't.Rank
@SteveC you can use File.separator constant to build the string to be used as a pathCalla
I know that, but it is very ugly. In contrast, new File("src/test/resources") does the right thing on all platforms.Rank
Why not just use Path resourceDirectory = Paths.get("src","test","resources");?Ransell
@Ransell sure, it will make it OS independent. Feel free to update the answerCalla
Hmm, Paths.get("src", "test", "resources") and Paths.get("src/test/resources") work fine on Windows 10 for me. What am I doing wrong? =)Assimilative
This is actually the best and cleanest answerDessau
Doesn't work with a multi module maven project, since the current directory will be the parent directory for sub modules.Wirer
L
32

If it's a spring project, we can use the below code to get files from src/test/resource folder.

File file = ResourceUtils.getFile(this.getClass().getResource("/some_file.txt"));
Locular answered 31/8, 2016 at 7:17 Comment(1)
We can also inject by using @Value like @Value("classpath: some_file.txt") private Resource someResource; and then in the method, someResource.getFile() to get the file.Locular
C
18

I have a Maven3 project using JUnit 4.12 and Java8. In order to get the path of a file called myxml.xml under src/test/resources, I do this from within the test case:

@Test
public void testApp()
{
    File inputXmlFile = new File(this.getClass().getResource("/myxml.xml").getFile());
    System.out.println(inputXmlFile.getAbsolutePath());
    ...
}

Tested on Ubuntu 14.04 with IntelliJ IDE. Reference here.

Note

The prepending / symbol is necessary, because Class.getResource(String) won't necessarily reveal entire file path (missing) along with FileNotFoundException.

Crosby answered 27/4, 2016 at 10:34 Comment(0)
F
13

All content in src/test/resources is copied into target/test-classes folder. So to get file from test resources during maven build you have to load it from test-classes folder, like that:

Paths.get(
    getClass().getProtectionDomain().getCodeSource().getLocation().toURI()
).resolve(
    Paths.get("somefile")
).toFile()

Break down:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI() - give you URI to target/test-classes.
  2. resolve(Paths.get("somefile")) - resolves someFile to target/test-classes folder.

Original anwser is taken from this

Flittermouse answered 5/5, 2018 at 8:36 Comment(0)
F
10

There are differences and constraints in options offered by @Steve C and @ashosborne1. They must be specified, I believe.

When can we can use: File resourcesDirectory = new File("src/test/resources");?

  • 1 When tests are going to be run via maven only but not via IDE.
  • 2.1 When tests are going to be run via maven or
  • 2.2 via IDE and only one project is imported into IDE. (I use “imported” term, cause it is used in IntelliJ IDEA. I think users of eclipse also import their maven project). This will work, cause working directory when you run tests via IDE is the same as your project.
  • 3.1 When tests are going to be run via maven or
  • 3.2 via IDE, and more than one projects are imported into IDE (when you are not a student, you usually import several projects), AND before you run tests via IDE, you manually configure working directory for your tests. That working directory should refer to your imported project that contains the tests. By default, working directory of all projects imported into IDE is only one. Probably it is a restriction of IntelliJ IDEA only, but I think all IDEs work like this. And this configuration that must be done manually, is not good at all. Working with several tests existing in different maven projects, but imported into one big “IDE” project, force us to remember this and don’t allow to relax and get pleasure from your work.

Solution offered by @ashosborne1 (personally I prefer this one) requires 2 additional requirements that must be done before you run tests. Here is a list of steps to use this solution:

  • Create a test folder (“teva”) and file (“readme”) inside of “src/test/resources/”:

    src/test/resources/teva/readme

    File must be created in the test folder, otherwise, it will not work. Maven ignores empty folders.

  • At least once build project via mvn clean install. It will run tests also. It may be enough to run only your test class/method via maven without building a whole project. As a result your test resources will be copied into test-classes, here is a path: target/test-classes/teva/readme

  • After that, you can access the folder using code, already offered by @ashosborne1 (I'm sorry, that I could not edit this code inside of this list of items correctly):

public static final String TEVA_FOLDER = "teva"; ... 
URL tevaUrl = YourTest.class.getClassLoader().getResource(TEVA_FOLDER); 
String tevaTestFolder = new File(tevaUrl.toURI()).getAbsolutePath();

Now you can run your test via IDE as many times as you want. Until you run mvn clean. It will drop the target folder.

Creating file inside a test folder and running maven first time, before you run tests via IDE are needed steps. Without these steps, if you just in your IDE create test resources, then write test and run it via IDE only, you'll get an error. Running tests via mvn copies test resources into target/test-classes/teva/readme and they become accessible for a classloader.

You may ask, why do I need import more than one maven project in IDE and why so many complicated things? For me, one of the main motivation: keeping IDA-related files far from code. I first create a new project in my IDE. It is a fake project, that is just a holder of IDE-related files. Then, I import already existing maven projects. I force these imported projects to keep IDEA files in my original fake project only. As a result I don't see IDE-related files among the code. SVN should not see them (don't offer to configure svn/git to ignore such files, please). Also it is just very convenient.

Fondle answered 8/6, 2016 at 16:9 Comment(4)
Hi Alexandr, i'm in trouble with Resource file in target/classes and src/main/resource and you seem the only one talk about it. First I have files on src/main/resource, after build project, it copy these file to target/classes. And from this, getClass().getClassLoader().getResource(fileName) only work on target folder while I want I work on src/main. Can you give me link somewhere explain about mechanism of getResource file? how to config Resource folder? Tks :DSuzannesuzerain
@Huy Hóm Hỉnh, I would recommend do not do it. I am afraid you go into the wrong direction.There are certain places where resource files are located, the places are known for all other. Easier to maintain such projects. Even for you it will be easier, you just need to understand the structure of maven projects. But for sure, you can configure default resource location with [maven.apache.org/plugins/maven-resources-plugin/examples/…Fondle
@HuyHómHỉnh, Also have a look at the solution here: #23289598 But to configure you src/main as a resource... Try to avoid it, it seems you do something wrong.Fondle
hm. Could you elaborate what's wrong with .gitignore? Also it looks like IDEA runs Maven automatically when running tests (and sets correct working dir by default, $MODULE_DIR$). So there is no need to run mvn test manually before that, everything works fine from both Maven and IDEA with just "src/test/resources/somefile.txt".Nisa
B
6

The simplest and clean solution I uses, suppose the name of the test class is TestQuery1 and there is a resources directory in your test folder as follows:

├── java
│   └── TestQuery1.java
└── resources
    └── TestQuery1
        ├── query.json
        └── query.rq

To get the URI of TestQuery1 do:

URL currentTestResourceFolder = getClass().getResource("/"+getClass().getSimpleName());

To get the URI of one of the file TestQuery1, do:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");
Bruckner answered 18/3, 2017 at 13:21 Comment(1)
No worries, in fact thank you for your help !! The good thing is that deleting your answer,I am able to delete the question. Yeah, quite frustrated out here also, but anyway thanks !! Good evening :)Bruckner
J
5

You can get where you are through

new File(".").getAbsolutePath()

then you can derive path to src/test/resources
usually it is just

new File("src/test/resources")
Jameyjami answered 20/2, 2021 at 13:48 Comment(0)
I
4

You can't use a file from a resource folder for tests in a common case. The reason is that resource files in the resource folder are stored inside a jar. So they don't have a real path in the file system.

The most simple solution can be:

  1. Copy a file from resources to the temporary folder and get a path to that temporary file.
  2. Do tests using a temporary path.
  3. Delete the temporary file.

TemporaryFolder from JUnit can be used to create temporary files and delete it after test is complited. Classes from guava library are used to copy a file form resource folder.

Please, notice that if we use a subfolder in the resources folder, like good one, we don't have to add leading / to the resource path.

public class SomeTest {

    @Rule
    public TemporaryFolder tmpFolder = new TemporaryFolder();


    @Test
    public void doSomethinge() throws IOException {
        File file = createTmpFileFromResource(tmpFolder, "file.txt");
        File goodFile = createTmpFileFromResource(tmpFolder, "good/file.txt");

        // do testing here
    }

    private static File createTmpFileFromResource(TemporaryFolder folder,
                                                  String classLoaderResource) throws IOException {
        URL resource = Resources.getResource(classLoaderResource);

        File tmpFile = folder.newFile();
        Resources.asByteSource(resource).copyTo(Files.asByteSink(tmpFile));
        return tmpFile;
    }

}
Igal answered 6/9, 2018 at 12:39 Comment(0)
M
3

With Spring you could easily read it from the resources folder (either main/resources or test/resources):

For example create a file: test/resources/subfolder/sample.json

@Test
public void testReadFile() {
    String json = this.readFile("classpath:subfolder/sample.json");
    System.out.println(json);
}

public String readFile(String path) {
    try {
        File file = ResourceUtils.getFile(path);
        return new String(Files.readAllBytes(file.toPath()));
    } catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}
Matriculate answered 8/1, 2020 at 9:14 Comment(0)
G
2

Wow the correct answer is not here yet!

MyClass.class.getResource("/somefile");
MyClass.class.getResourceAsStream("/somefile");

https://javachannel.org/posts/how-to-access-static-resources/

Gretchen answered 24/11, 2021 at 5:50 Comment(0)
N
0

Use .getAbsolutePath() on your File object.

getClass().getResource("somefile").getFile().getAbsolutePath()
Nepheline answered 20/10, 2017 at 15:30 Comment(3)
getFile return String instance not FIleNicholson
@AlmasAbdrazak GreatDantone doesn't say that getFile() returns an instance of file. He says that getAbsolutePath() is used on an instance of File object.Mcmillan
@Mcmillan According to his code, he calls getFile() and then getAbsolutePath() on getFile() but getFile() returns String and you can't call getAbsolutePath() on String objectNicholson
F
0

Use the following to inject Hibernate with Spring in your unit tests:

@Bean
public LocalSessionFactoryBean getLocalSessionFactoryBean() {
    LocalSessionFactoryBean localSessionFactoryBean = new LocalSessionFactoryBean();
    localSessionFactoryBean.setConfigLocation(new ClassPathResource("hibernate.cfg.xml"));
    localSessionFactoryBean.setPackagesToScan("com.example.yourpackage.model");
    return localSessionFactoryBean;
}

If you don't have the hibernate.cfg.xml present in your src/test/resources folder it will automatically fall back to the one in your src/main/resources folder.

Falbala answered 31/1, 2018 at 8:12 Comment(0)
M
0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
Mundford answered 5/6, 2020 at 2:43 Comment(0)
E
0

With Spring, you can use this:

import org.springframework.core.io.ClassPathResource;

// Don't worry when use a not existed directory or a empty directory
// It can be used in @before
String dir = new ClassPathResource(".").getFile().getAbsolutePath()+"/"+"Your Path";
Exemplification answered 23/10, 2020 at 9:33 Comment(0)
B
0

Here is some helper functions when using Kotlin language:

private val resourceAccessor = object {}

fun getResourceAsPath(name: String): Path = resourceAccessor
    .javaClass
    .getResource("/$name")!!
    .toURI()
    .toPath()

fun getResourceAsURL(name: String): URL {
    val testResourcesDirectory = Path("src/test/resources").absolutePathString()
    return URL("file:$testResourcesDirectory/$name")
}
class MyTests {
    @Test
    fun myTest() {
        val myResource = getResourceAsPath("file.txt")
        val absolutePath = myResource.absolutePathString()
    }
}
Bournemouth answered 8/9, 2023 at 7:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.