在使用Maven进行单元测试期间,写入临时文件的正确方法是什么?


70

我编写了一个单元测试,将文件写入文件系统,没有给它写入工作目录的路径。因此,如果从项目目录执行,它将写入项目根目录;如果在项目父目录中,它将写入父目录根目录。

那么写入目标目录的正确方法是什么?可能是目标目录中的目录?

如果我只是简单地target/用文件指定,它将写入父项目目标而不是项目目标。

更新:我实际上想要测试完成后的文件。该文件是第三方的提取格式,需要将其发送给第三方。可以打开/关闭该测试,以允许我仅在文件格式更改为要重新批准时才能运行。文件存放在哪里并不是一个大问题,但是我希望找到一个容易找到的东西。

Answers:


76

您可以按此处所述尝试使用TemporaryFolder JUnit @Rule

TemporaryFolder创建由系统属性java.io.tmpdir指定的默认临时文件目录的文件夹。方法newFile在临时目录中创建一个新文件,而newFolder方法创建一个新文件夹。

测试方法完成后,JUnit会自动删除TemporaryFolder中(包括其中)的所有文件和目录。无论测试是通过还是失败,JUnit都保证删除资源。


问题更新后

您可以更改所使用的工作目录maven-surefire-plugin

<plugins>
    [...]
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.3</version>
        <configuration>
          <workingDirectory>${project.build.directory}</workingDirectory>
        </configuration>
      </plugin>
    [...]
</plugins>

您可以将该工作目录更改为测试所需的任何目录,例如${project.build.directory}/my_special_dir/

surefire插件中的工作目录仅影响正在运行的测试,仅影响由maven进行的测试。如果从IDE内运行测试,则工作目录将是其他目录。


谢谢maba,这是与Bohemian类似的问题,文件最终位于不明显的位置。测试结束后,我实际上想要该文件。
Brett Ryan

@BrettRyan OK,已更新有关如何更改surefire插件的工作目录的信息。这应该够了吧。
马巴2012年

太棒了,谢谢maba,它非常完美,并且在运行测试的所有计算机上始终保持一致。
Brett Ryan

1
感谢您留下原始答案。那就是我所需要的。
yellavon 2014年

JUNIT不保证必须自动删除@Rule公共TemporaryFolder文件夹= TemporaryFolder.builder()。assureDeletion()。build();
vimal krishna

47

无需重新发明轮子...

JDK提供了一种创建临时文件的方法,以及一种在退出时自动将其删除的方法:

File file = File.createTempFile( "some-prefix", "some-ext");
file.deleteOnExit();

使用该文件,测试完成后它将自动删除。这里的所有都是它的。

要指定用于临时文件的目录,请使用重载方法:

File file = File.createTempFile( "prefix", "ext", new File("/some/dir/path"));

多亏了Bohemian,我实际上希望文件在退出后仍然存在,因此可以将其发送给供应商。我想系统临时目录很好,尽管我确实希望将其放在目标目录中。
Brett Ryan

我刚刚尝试过,结果证明文件位于一个晦涩难懂的地方,使用起来并不明智。结束于/var/folders/xf/scvh7yr11m1glr4b663n1hcsnv5lf0/T/test2614442099335581603.xml
布雷特·瑞安

4
@BrettRyan没问题-您可以指定用于临时文件的目录-请参见编辑后的答案
Bohemian

感谢Bohemian,我确实能够设置temp目录,尽管我确实喜欢将其放置在目标目录下可靠位置中的能力,而不是需要在计算机上存在特定位置。
Brett Ryan

2

我将编写一个例程,该例程确定文件应写入的位置,此后我将其统一,通常,我会尽量避免(尽可能)在单元测试中访问持久性数据,例如文件IO或数据库访问,这有性能原因,还有其他。

看看这个解决方案:https ://stackoverflow.com/a/8032504/395659


感谢OD,直到现在我再也不需要做这种事情。我编写了测试以编写一个文件,该文件将以生产代码的形式发送给其他供应商。我的测试将文件写入磁盘,供我发送给供应商以供批准。批准后,将不需要该测试,但是稍后在发生某些更改并需要“重新批准”输出时可能会很有用。
Brett Ryan

2
但是为什么要为此目的使用“单元测试”?我认为,即使使用main()方法使用单独的类来实现此目的,也比滥用单元测试更合适
Adrian Shum 2012年

2

您将希望能够从IDE以及从Maven都运行测试,因此最佳实践是编写测试,以免它们假定它们在Maven中运行。

处理临时文件的最佳方法之一是使用junit规则。这使您可以依靠规则为您进行清理。


2

事先声明一下,我强烈反对在单元测试中进行此类操作。我还没有真正尝试过,但是应该可以:

假设您使用的是surefire插件,从引用的文档中,您可以通过来访问被测项目的基本目录System.getProperty("basedir")。获取它并在basedir / target下创建文件。

一种更“合适”的方式(因为我们可能会将输出目录配置为其他目录,因此可以将surefire插件配置更改为如下所示:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <systemPropertyVariables>
            <myOutDir>${project.build.outputDirectory}</myOutDir>
        </systemPropertyVariables>
    </configuration>
</plugin>

然后,您可以System.getProperty("myOutDir")在测试中获得实际的输出目录。


1

临时文件应创建到临时目录中。使用通话检索System.getProperty("java.io.tmpdir")

临时文件应该是临时文件,即在不需要文件时将其删除。为了做到这一点,请不要忘记finally在测试后运行的代码块或代码中删除它,即:

File tmpFile = ...
try {
   // deal with tempFile
} finally {
    tempFile.delete();
}

和/或

public class MyTestCase {
    private File tmpFile = null;

    @Before
    public void setUp() {
        tmpFile = ...;
    }

    @Test
    public void setUp() {
        // deal with tmpFile
    }

    @After
    public void setUp() {
        tmpFile.delete();
    }
}

File.createTempFile(String prefix, String suffix)如果可能,请使用,即可以使用由生成的特殊名称的文件createTempFile()

使用file.deleteOnExit()。这将创建挂钩,当JVM终止时,该挂钩会自动删除文件。仅当JVM被杀死时kill -9,该文件才会保留,因此它没有机会运行关闭代码。

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.