如何在JUnit中获取src / test / resources目录的路径?


275

我知道我可以使用以下命令从src / test / resources加载文件:

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

但是,如何获得src / test / resources 目录的完整路径,即我不想加载文件,我只想知道目录的路径?


1
出于好奇:您为什么想知道?
fge

3
@fge需要将其传递给被测对象,后者使用它来加载文件
Rory

5
直接文件访问资源目录是一个坏主意。重构代码以快速运行,或者让您的测试首先在TemporaryFolder中创建副本。
奥利弗·查尔斯沃思

4
@OliverCharlesworth我同意临时文件夹并一直使用org.junit.rules.TemporaryFolder...但是...要从测试/资源中复制,您需要知道它的路径!
麦克啮齿动物'18

1
@mikerodent-我的意思是:通过输入流读取资源,然后将其写入临时文件。
奥利弗查尔斯沃思'18

Answers:


204

尝试与ClassLoader班级一起工作:

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

A ClassLoader负责加载类。每个类都有对的引用ClassLoader。此代码File从资源目录返回a 。调用getAbsolutePath()它会返回其absolute Path

适用于的Javadoc ClassLoaderhttp : //docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html


34
这不一定是个好主意。如果资源位于Jar中,这将导致不幸的时刻。
奥利弗·查尔斯沃思

1
@OliverCharlesworth那么,如果使用jar,该怎么办?
Anmol Singh Jaggi '10

@AnmolSinghJaggi-看到我在原始问题下方的评论:)
奥利弗·查尔斯沃思

当我使用此解决方案时,Maven构建失败
firstpostcommenter

它也将带有文件名
qwert_ukg '18

299

您无需弄乱类加载器。实际上,这是一个坏习惯,因为当类加载器资源放在jar存档中时,它们不是 java.io.File对象。

Maven在运行测试之前会自动设置当前工作目录,因此您可以使用:

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

resourcesDirectory.getAbsolutePath() 如果这正是您真正需要的,它将返回正确的值。

src/test/data如果您希望测试通过文件系统访问数据,我建议创建一个目录。这样可以清楚地说明您在做什么。


4
新File(“ src / test / resources / fileXYZ”); 不管用。如果只是将其放入JUnit测试中,那么无论是来自Eclipse还是来自Maven。
seba.wagner,2015年

11
它可以从Maven正常工作。在eclipse中,您需要在测试运行器中设置当前的工作目录,但是命令行maven会为您执行此操作。
史蒂夫C

4
我不这么认为。而且,如果您只需做一个“ new File(getClass()。getClassLoader()。getResource(“ fileNameXYZ.xml”)”而无需进行任何设置,那么为什么要这样做,无论是在Eclipse中还是在Maven中都没有。)
seba .wagner 2015年

10
相反,您为什么不遵循构建实用程序的标准?特别是当它简化您的代码时。使用IntelliJ或Maven,无需设置工作目录。显然,这是最简单的解决方案,而Eclipse总是很痛苦。
詹姆斯·沃特金斯

2
对于IntelliJ 2014版本,我仍然必须更改测试方法/类的“运行/调试”配置中的工作目录,如@Steve C所述。
a_secenthusiast

76

我只是Path在Java 7中使用

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

干净整洁!


在Windows上可以使用完全相同的代码吗?JavaDoc for Paths.get(...)暗示(无论如何对我来说)它不会。
史蒂夫·C

@SteveC您可以使用File.separator常量来构建用作路径的字符串
JeanValjean

1
我知道,但是非常丑陋。相反,new File("src/test/resources")在所有平台上都做正确的事。
史蒂夫C

2
为什么不只是使用Path resourceDirectory = Paths.get("src","test","resources");
Navneeth '17

1
嗯,Paths.get("src", "test", "resources")Paths.get("src/test/resources")在Windows 10的工作对我罚款。我究竟做错了什么?=)
naXa

24

如果这是一个春季项目,我们可以使用以下代码从src / test / resource文件夹中获取文件。

File file = ResourceUtils.getFile(this.getClass().getResource("/some_file.txt"));

14

我有一个使用JUnit 4.12和Java8的Maven3项目。为了获得一个名为myxml.xmlunder 的文件的路径src/test/resources,我从测试用例中执行以下操作:

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

使用IntelliJ IDE在Ubuntu 14.04上进行了测试。参考这里


11

中的所有内容src/test/resources都将复制到target/test-classes文件夹中。因此,要在Maven构建期间从测试资源中获取文件,您必须从test-classes文件夹中加载文件,如下所示:

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

分解:

  1. getClass().getProtectionDomain().getCodeSource().getLocation().toURI()-为您提供URI target/test-classes
  2. resolve(Paths.get("somefile"))-解析someFiletarget/test-classes文件夹。

原始的anwser从这里


8

@Steve C和@ ashosborne1提供的选项存在差异和约束。我认为必须指定它们。

我们File resourcesDirectory = new File("src/test/resources");什么时候可以使用:

  • 1当仅通过maven而不是通过IDE运行测试时。
  • 2.1当要通过Maven或
  • 通过IDE 2.2,只有一个项目导入到IDE。(我使用“导入”术语,因为它在IntelliJ IDEA中使用。我认为eclipse的用户也导入了他们的maven项目)。这将起作用,因为通过IDE运行测试时,工作目录与项目相同。
  • 3.1当要通过maven或
  • 通过IDE 3.2,并且将多个项目导入到IDE中(当您不是学生时,通常会导入多个项目),并且在通过IDE运行测试之前,您需要为测试手动配置工作目录。该工作目录应该引用包含测试的导入项目。默认情况下,导入到IDE中的所有项目的工作目录只有一个。可能IntelliJ IDEA只有一个限制,但我认为所有IDE都可以这样工作。这种必须手动完成的配置根本不好。使用不同maven项目中存在的但已导入一个大型“ IDE”项目中的多个测试,迫使我们记住这一点,并且不允许您放松身心并从工作中获得乐趣。

@ ashosborne1提供的解决方案(我个人更喜欢这一点)要求在运行测试之前必须完成两个附加要求。以下是使用此解决方案的步骤列表:

  • 在“ src / test / resources /”内部创建一个测试文件夹(“ teva”)和文件(“ readme”):

    src / test / resources / teva / readme

    必须在测试文件夹中创建文件,否则将无法使用。Maven忽略空文件夹。

  • 至少一次通过构建项目mvn clean install。它还将运行测试。仅通过maven运行您的测试类/方法而不构建整个项目就足够了。结果,您的测试资源将被复制到测试类中,这是一条路径:target/test-classes/teva/readme

  • 之后,您可以使用@ ashosborne1已提供的代码访问文件夹(很抱歉,我无法在此项目列表内正确编辑此代码):

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

现在,您可以根据需要多次通过IDE运行测试。直到您运行mvn clean。它将删除目标文件夹。

在通过IDE运行测试之前,需要在测试文件夹中创建文件并首次运行maven。如果不执行这些步骤,如果仅在IDE中创建测试资源,然后编写测试并仅通过IDE运行它,则会出现错误。通过mvn运行测试会将测试资源复制到目标/测试类/ teva /自述文件中,并且类加载器可以访问它们。

您可能会问,为什么我需要在IDE中导入多个maven项目,为什么会有那么多复杂的东西?对我而言,主要动机之一是:使与IDA相关的文件远离代码。我首先在IDE中创建一个新项目。这是一个伪项目,只是IDE相关文件的持有者。然后,导入已经存在的Maven项目。我强迫这些导入的项目将IDEA文件仅保留在我的原始伪项目中。结果,我在代码中看不到与IDE相关的文件。SVN应该看不到它们(请不要提供将svn / git配置为忽略此类文件)。而且这只是非常方便。


嗨,亚历山大,我在target / classes和src / main / resource中的Resource文件遇到了麻烦,您似乎是唯一谈论它的人。首先,我在src / main / resource上有文件,在构建项目后,它将这些文件复制到目标/类。从这个,getClass()。getClassLoader()。getResource(fileName)只在目标文件夹上工作,而我想在src / main上工作。您能给我链接解释一下getResource文件的机制吗?如何配置资源文件夹?Tks:D
HuyHómHỉnh'18

2
@HuyHómHỉnh,我建议不要这样做。恐怕您会走错方向。在某些位置放置了资源文件,而这些位置对于所有其他位置都是已知的。更容易维护此类项目。即使对您而言,它也会变得更加容易,您只需要了解Maven项目的结构即可。但是可以肯定的,你可以用[配置默认资源位置maven.apache.org/plugins/maven-resources-plugin/examples/...
亚历山大

@HuyHómHỉnh,也请在此处查看解决方案:stackoverflow.com/questions/23289098 / ...但是要将src / main配置为资源...尝试避免它,看来您做错了什么。
亚历山大

嗯。您能详细说明出什么问题.gitignore吗?而且看起来IDEA在运行测试时会自动运行Maven(并默认设置正确的工作目录$MODULE_DIR$)。因此,mvn test在此之前无需手动运行,只要使用,Maven和IDEA的所有功能都可以正常运行"src/test/resources/somefile.txt"
Alex P.

5

我使用的最简单,干净的解决方案是,假设测试类的名称为,TestQuery1并且文件夹中有一个resources目录,test如下所示:

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

要获取TestQuery1do 的URI :

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

要获取文件之一的URI TestQuery1,请执行以下操作:

File exampleDir = new File(currentTestResourceFolder.toURI());
URI queryJSONFileURI = exampleDir.toURI().resolve("query.json");

1
不用担心,实际上感谢您的帮助!好在删除您的答案,我可以删除问题。是的,在这里也很沮丧,但是无论如何,谢谢!晚上好:)
Noor

1

在常见情况下,您不能使用资源文件夹中的文件进行测试。原因是资源文件夹中的资源文件存储在jar中。因此,它们在文件系统中没有真实路径。

最简单的解决方案可以是:

  1. 将文件从资源复制到临时文件夹,并获取该临时文件的路径。
  2. 使用临时路径进行测试。
  3. 删除临时文件。

TemporaryFolderfrom JUnit可用于创建临时文件,并在测试完成后将其删除。guava库中的类用于复制文件表单资源文件夹。

请注意,如果我们在资源文件夹中使用一个子文件夹,例如good一个子文件夹,则不必添加引号/到资源路径。

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

}

0

使用以下代码在单元测试中注入带有Spring的Hibernate:

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

如果文件夹中没有hibernate.cfg.xml礼物,src/test/resources它将自动退回到文件夹中的礼物src/main/resources


0

在File对象上使用.getAbsolutePath()。

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

getFile返回字符串实例不是文件
Almas Abdrazak

@AlmasAbdrazak GreatDantone不会getFile()返回文件实例。他说这getAbsolutePath()是在File对象的实例上使用的。
menteith

@menteith根据他的代码,他先调用getFile(),然后再调用getFile()上的getAbsolutePath(),但是getFile()返回String,而您不能调用String对象上的getAbsolutePath()
Almas Abdrazak

0

使用Spring,您可以轻松地从resources文件夹(main / resources或test / resources)中读取它:

例如创建一个文件: 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;
}

0
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.