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

问题描述 投票:0回答:8

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

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

如果我简单地用文件指定

target/
,它将写入父项目目标而不是项目目标。

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

java maven unit-testing junit4 junit5
8个回答
84
投票

您可以尝试使用TemporaryFolder JUnit @Rule,如此处

所述

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

当测试方法完成时,JUnit 会自动删除 TemporaryFolder 中的所有文件和目录(包括 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 中运行测试,工作目录将是其他目录。


64
投票

无需重新发明轮子...

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

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

使用该文件,测试完成后它将自动删除。这就是全部内容了。

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

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

4
投票

从 JUnit 5 开始,您可以使用 @TempDir。测试结束后将被删除(包括其内容)。

每个测试一个临时目录:

@Test
void testWithTempFiles(@TempDir Path tempDir) 
    Path file = tempDir.resolve("temp_file.txt");
    ...
}

或班级中所有测试的单个测试:

@TempDir
static Path tempDir

@Test
void testWithTempFiles() 
    Path file = tempDir.resolve("temp_file.txt");
    ...
}

2
投票

我会编写一个例程来确定文件应该写入哪里,之后我会对其进行统一测试,一般来说,我会尽量避免(尽可能)在单元测试中访问持久数据,例如文件IO或数据库访问,这有性能原因和其他原因也是。

看看这个问题:https://stackoverflow.com/a/8032504/395659


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 终止时会自动删除文件。仅当使用
kill -9
终止 JVM 时,该文件才会保留,因此它没有机会运行关闭代码。


0
投票

以下是使用 JUnit 5 和 Kotlin 语言的几种方法。

  • 在字段上使用 JUnit 5

    @TempDir

    @TempDir(cleanup = ON_SUCCESS)
    lateinit var tempDirectory: Path
    
    @Test fun example() {
        // use the tempDirectory
    }
    
  • 在测试函数参数上使用 JUnit 5

    @TempDir

    @Test fun example(
        @TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDirectory: Path
    ) {
        // use the tempDirectory
    }
    
  • 手动创建文件并调用

    deleteOnExit()
    :

    @Test fun example() {
        val file = File("file.txt").apply { deleteOnExit() }
    }
    
  • 在测试类或测试函数中使用 Kotlin

    createTempDirectory
    createTempFile
    函数:

    val file = createTempFile("file.txt")
    
© www.soinside.com 2019 - 2024. All rights reserved.