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

Posted

技术标签:

【中文标题】如何在 JUnit 中获取 src/test/resources 目录的路径?【英文标题】:How to get the path of src/test/resources directory in JUnit? 【发布时间】:2015-04-24 18:27:08 【问题描述】:

我知道我可以从 src/test/resources 加载文件:

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

但是我怎样才能得到src/test/resources目录的完整路径,即我不想加载文件,我只想知道目录的路径?

【问题讨论】:

出于好奇:你为什么想知道? @fge 需要将它传递给被测对象,它使用它来加载文件 直接文件访问你的资源目录是个坏主意。重构您的代码以在 Steam 上运行,或者让您的测试首先在 TemporaryFolder 中创建一个副本。 @OliverCharlesworth 我同意临时文件夹并一直使用org.junit.rules.TemporaryFolder...但是...从您需要知道的测试/资源中复制,呃,它的路径! @mikerodent - 我认为的意思是:通过输入流读取资源,然后将其写入临时文件。 【参考方案1】:

尝试使用ClassLoader 类:

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

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

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

【讨论】:

这不一定是个好主意。如果资源在 Jar 中,这将导致悲伤。 @OliverCharlesworth 那么,遇到 jar 怎么办? @AnmolSinghJaggi - 请参阅我在原始问题下方的评论:) 使用此解决方案时,maven 构建失败 文件名也可以【参考方案2】:

你不需要弄乱类加载器。事实上,这是一个不好的习惯,因为类加载器资源在 jar 存档中时不是 java.io.File 对象。

Maven 会在运行测试前自动设置当前工作目录,所以你可以直接使用:

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

resourcesDirectory.getAbsolutePath() 将返回您真正需要的正确值。

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

【讨论】:

新文件("src/test/resources/fileXYZ");不管用。如果您只是将其放入 JUnit 测试中,则既不是来自 Eclipse 也不是来自 Maven。 它在 Maven 中运行良好。在 Eclipse 中,您需要在测试运行程序中设置当前工作目录,但命令行 maven 会为您完成此操作。 我不这么认为。如果您可以简单地执行“new File(getClass().getClassLoader().getResource("fileNameXYZ.xml")”而不需要任何设置,那么您为什么要这样做。在 Eclipse 和 Maven 中都没有。跨度> 相反,您为什么不遵循构建实用程序的标准?特别是当它简化您的代码时。使用 IntelliJ 或 Maven,无需设置工作目录。这显然是最简单的解决方案,Eclipse 一如既往的痛苦。 对于 IntelliJ 2014 版本,我仍然必须更改测试方法/类的运行/调试配置中的工作目录,正如@Steve C 提到的那样。【参考方案3】:

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

@Test
public void testApp()

    File inputXmlFile = new File(this.getClass().getResource("/myxml.xml").getFile());
    System.out.println(inputXmlFile.getAbsolutePath());
    ...

在 Ubuntu 14.04 上使用 IntelliJ IDE 进行测试。 参考here。

【讨论】:

【参考方案4】:

@Steve C 和@ashosborne1 提供的选项存在差异和限制。我相信它们必须被指定。

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

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

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

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

src/test/resources/teva/readme

必须在 test 文件夹中创建文件,否则将无法正常工作。 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 运行测试会将测试资源复制到 target/test-classes/teva/readme 中,并且它们可供类加载器访问。

你可能会问,为什么我需要在 IDE 中导入多个 maven 项目,为什么要导入这么多复杂的东西?对我来说,主要动机之一是:让 IDA 相关文件远离代码。我首先在我的 IDE 中创建一个新项目。这是一个假项目,只是 IDE 相关文件的持有者。然后,我导入已经存在的 Maven 项目。我强制这些导入的项目仅将 IDEA 文件保留在我原来的假项目中。因此,我在代码中看不到与 IDE 相关的文件。 SVN 不应该看到它们(请不要将 svn/git 配置为忽略此类文件)。也很方便。

【讨论】:

嗨,Alexandr,我在 target/classes 和 src/main/resource 中的资源文件遇到了麻烦,你似乎只有一个人在谈论它。首先我在 src/main/resource 上有文件,在构建项目之后,它将这些文件复制到目标/类。由此,getClass().getClassLoader().getResource(fileName) 仅适用于目标文件夹,而我希望我适用于 src/main。你能给我链接解释一下getResource文件的机制吗?如何配置资源文件夹? Tks :D @Huy Hóm Hỉnh,我建议不要这样做。恐怕你走错了方向。资源文件所在的某些地方,其他地方都是众所周知的。更容易维护这样的项目。即使对你来说它会更容易,你只需要了解 maven 项目的结构。但可以肯定的是,您可以使用 [maven.apache.org/plugins/maven-resources-plugin/examples/… 配置默认资源位置 @HuyHómHỉnh,也看看这里的解决方案:***.com/questions/23289098/… 但是要将你的 src/main 配置为资源......尽量避免它,似乎你做错了什么。跨度> 嗯。你能详细说明.gitignore 有什么问题吗?此外,IDEA 似乎在运行测试时会自动运行 Maven(并默认设置正确的工作目录,$MODULE_DIR$)。因此,在此之前无需手动运行mvn test,只需"src/test/resources/somefile.txt",Maven 和 IDEA 都可以正常运行。【参考方案5】:

如果是spring项目,我们可以使用下面的代码从src/test/resource文件夹中获取文件。

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

【讨论】:

我们也可以像@Value("classpath: some_file.txt") private Resource someResource;一样使用@Value注入,然后在方法中someResource.getFile()获取文件。【参考方案6】:

我会简单地使用 Java 7 中的 Path

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

干净整洁!

【讨论】:

这个完全相同的代码可以在 Windows 上运行吗? Paths.get(...) 的 JavaDoc 建议(无论如何对我来说)它不会。 @SteveC 你可以使用File.separator 常量来构建用作路径的字符串 我知道,但它很丑。相比之下,new File("src/test/resources") 在所有平台上都是正确的。 为什么不直接使用Path resourceDirectory = Paths.get("src","test","resources"); 嗯,Paths.get("src", "test", "resources")Paths.get("src/test/resources") 对我来说在 Windows 10 上运行良好。我究竟做错了什么? =)【参考方案7】:

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

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

要获取TestQuery1 的 URI,请执行以下操作:

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

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

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

【讨论】:

不用担心,其实谢谢你的帮助!!好消息是删除您的答案,我可以删除问题。是的,在这里也很沮丧,但无论如何谢谢!晚上好:)【参考方案8】:

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

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

【讨论】:

getFile 返回字符串实例不是文件 @AlmasAbdrazak GreatDantone 并没有说getFile() 返回文件的实例。他说getAbsolutePath() 用于 File 对象的实例。 @menteith 根据他的代码,他在 getFile() 上调用 getFile() 然后 getAbsolutePath() 但 getFile() 返回 String 并且您不能在 String 对象上调用 getAbsolutePath() 【参考方案9】:

在您的单元测试中使用以下方法通过 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;

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

【讨论】:

【参考方案10】:

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

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

分解:

    getClass().getProtectionDomain().getCodeSource().getLocation().toURI() - 给你 target/test-classes 的 URI。 resolve(Paths.get("somefile")) - 将 someFile 解析为 target/test-classes 文件夹。

原始答案取自this

【讨论】:

【参考方案11】:

在一般情况下,您不能使用资源文件夹中的文件进行测试。原因是资源文件夹中的资源文件存储在 jar 中。所以他们在文件系统中没有真正的路径。

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

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

JUnit 中的TemporaryFolder 可用于创建临时文件并在测试完成后将其删除。 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;
    


【讨论】:

【参考方案12】:

使用 Spring,您可以轻松地从资源文件夹(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;

【讨论】:

【参考方案13】:
List<String> lines = Files.readAllLines(Paths.get("src/test/resources/foo.txt"));
lines.forEach(System.out::println);

【讨论】:

【参考方案14】:

有了 Spring,你可以这样使用:

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

【讨论】:

【参考方案15】:

你可以通过它到达你所在的地方

new File(".").getAbsolutePath()

然后你可以导出到 src/test/resources 的路径 通常只是

new File("src/test/resources")

【讨论】:

【参考方案16】:

哇,还没有正确答案!

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

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

【讨论】:

以上是关于如何在 JUnit 中获取 src/test/resources 目录的路径?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用maven获取依赖jar的路径

如何在 android 的 JUnit 测试用例中获取 MainActivity 的上下文和活动?

如何解析JUnit结果xml文件并在java代码中获取testcase?

获取在 Junit 中自动装配的 @ConfigurationProperties bean

如何在spring或使用junit获取rest api的执行时间(获得响应的时间)

如何在 Spring Junit 中创建会话