2年前 (2023-04-10)  Java系列 |   抢沙发  381 
文章评分 0 次,平均分 0.0

测试时,我们通常需要访问一个临时文件。然而,自己管理这些文件的创建和删除可能会很麻烦。

在本问中,我们将了解JUnit 5如何通过提供TempDirectory扩展来缓解这种情况。

有关JUnit测试的深入指南,请查看JUnit 5文档:https://junit.org/junit5/docs/current/user-guide/#overview

TempDirectory扩展

从5.4.2版本开始,JUnit 5提供了TempDirectory扩展。然而,重要的是要注意,从官方角度来看,这仍然是一个实验性功能,我们被鼓励向JUnit团队提供反馈。

正如我们稍后将看到的,我们可以使用此扩展为单个测试或测试类中的所有测试创建和清理临时目录。

通常,当使用扩展时,我们需要使用@ExtendeWith注释从JUnit5测试中注册它。但对于内置并默认注册的TempDirectory扩展来说,这是不必要的。

Maven依赖项

首先,让我们添加示例所需的项目依赖项。

除了主要的JUnit 5库JUnit jupiter引擎外,我们还需要JUnit jubiter api库:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

一如既往,我们可以从Maven Central获得最新版本。

除此之外,我们还需要添加junit jupiter params依赖项:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.9.2</version>
    <scope>test</scope>
</dependency>

同样,我们可以在Maven Central中找到最新版本。

使用@TempDir注释

为了使用TempDirectory扩展,我们需要使用@TempDir注释。我们只能将此注释与以下两种类型一起使用:

  • java.nio.file.Path
  • java.io.File

事实上,如果我们尝试将其与不同的类型一起使用,那么将抛出org.unit.jupiter.api.extension.ParameterResolutionException

接下来,让我们探讨使用此注释的几种不同方法。

@TempDir作为方法参数

让我们从如何将用@TempDir注释的参数注入单个测试方法开始:

@Test
void givenTestMethodWithTempDirectory_whenWriteToFile_thenContentIsCorrect(@TempDir Path tempDir) 
  throws IOException {
    Path numbers = tempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(numbers)),
      () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

正如我们所看到的,我们的测试方法在临时目录tempDir中创建并写入一个名为numbers.txt的文件。

然后,我们检查文件是否存在,以及内容是否与最初编写的内容相匹配。真的很简单!

@TempDir在实例字段上

在下一个示例中,我们将使用@TempDir注释来注释测试类中的字段:

@TempDir
File anotherTempDir;

@Test
void givenFieldWithTempDirectoryFile_whenWriteToFile_thenContentIsCorrect() throws IOException {
    assertTrue("Should be a directory ", this.anotherTempDir.isDirectory());

    File letters = new File(anotherTempDir, "letters.txt");
    List<String> lines = Arrays.asList("x", "y", "z");

    Files.write(letters.toPath(), lines);

    assertAll(
      () -> assertTrue("File should exist", Files.exists(letters.toPath())),
      () -> assertLinesMatch(lines, Files.readAllLines(letters.toPath())));
}

这一次,我们使用java.io.File作为临时目录。再次,我们写了一些行,并检查它们是否写成功。

如果我们在其他测试方法中再次使用这个单独的引用,那么每个测试都将使用自己的临时目录。

共享临时目录

有时,我们可能希望在测试方法之间共享一个临时目录。

我们可以通过声明字段为static来实现这一点:

@TempDir
static Path sharedTempDir;

@Test
@Order(1)
void givenFieldWithSharedTempDirectoryPath_whenWriteToFile_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    List<String> lines = Arrays.asList("1", "2", "3");
    Files.write(numbers, lines);

    assertAll(
        () -> assertTrue("File should exist", Files.exists(numbers)),
        () -> assertLinesMatch(lines, Files.readAllLines(numbers)));
}

@Test
@Order(2)
void givenAlreadyWrittenToSharedFile_whenCheckContents_thenContentIsCorrect() throws IOException {
    Path numbers = sharedTempDir.resolve("numbers.txt");

    assertLinesMatch(Arrays.asList("1", "2", "3"), Files.readAllLines(numbers));
  }

在第一次测试中,我们再次将一些行写入一个名为numbers.txt的文件。然后在下一次测试中检查该文件和内容是否已经存在。

我们还通过@order注释强制执行测试的顺序,以确保行为始终一致。

清理选项

通常,@TempDir创建的临时目录会在测试执行后自动删除。但是,在某些情况下,我们可能希望保留临时目录以进行调试。

例如,如果测试失败,我们可能需要检查临时目录的内容,看看是否有任何关于失败原因的线索。在这种情况下,Junit5自动删除临时目录可能是不可取的。

为了解决这个问题,Junit5为@TempDir注释提供了一个清理选项。cleanup选项可用于指定是否应在测试方法结束时自动删除临时目录。

清除选项可以设置为以下CleanupMode值之一:

  • ALWAYS–此选项指定无论测试成功还是失败,都应在测试方法结束时自动删除临时目录。这是默认模式。
  • ON_SUCCESS–只有在测试成功的情况下,才会在测试方法执行后删除临时目录。
  • NEVER–执行测试方法后,临时目录不会自动删除。

接下来,让我们创建一个测试类来验证如果我们将NEVER设置为清除选项的值,则在测试执行后不会删除临时目录:

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class TemporaryDirectoryWithCleanupUnitTest {

    private Path theTempDirToBeChecked = null;

    @Test
    @Order(1)
    void whenTestMethodWithTempDirNeverCleanup_thenSetInstanceVariable(@TempDir(cleanup = NEVER) Path tempDir) {
        theTempDirToBeChecked = tempDir;
        System.out.println(tempDir.toFile().getAbsolutePath());
    }

    @Test
    @Order(2)
    void whenTestMethodWithTempDirNeverCleanup_thenTempDirShouldNotBeRemoved() {
        assertNotNull(theTempDirToBeChecked);
        assertTrue(theTempDirToBeChecked.toFile().isDirectory());
    }

}

正如上面的类所示,我们向测试类添加了@TestInstance(TestInstance.Lifecycle.PER_CLASS)注释,以便JUnit只创建测试类的一个实例,并将其用于所有测试。这是因为我们将在第一次测试中设置TempDirToBeChecked实例变量,并在第二次测试中验证临时目录是否仍在。

如果我们运行测试,它就会通过。因此,它表明在第二次测试运行期间,在第一次测试中创建的临时目录不会被删除。

此外,我们可以看到第一次测试的输出:

/tmp/junit16624071649911791120

Junit5的INFO日志提醒我们,第一次测试后不会删除临时目录:

INFO: Skipping cleanup of temp dir /tmp/junit16624071649911791120 due to cleanup mode configuration.

在所有测试执行之后,如果我们检查文件系统上的临时目录,该目录仍然存在:

$ ls -ld /tmp/junit16624071649911791120
drwx------ 2 kent kent 40 Apr  1 18:23 /tmp/junit16624071649911791120/

现在,让我们回顾一下在使用TempDirectory扩展时应该注意的一些细微之处。

创建

好奇的读者很可能会想知道这些临时文件实际上是在哪里创建的?

在内部,JUnit TemporaryDirectory类使用了Files.createTempDirectory(String prefix)方法。同样,此方法也会使用默认的系统临时文件目录。

这通常在环境变量TMPDIR中指定:

TMPDIR=/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/

例如,导致临时文件位置:

/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/junit5416670701666180307/numbers.txt

同时,如果无法创建临时目录,则会根据情况抛出ExtensionConfigurationException。或者如前所述,ParameterResolutionException

删除

清除属性的默认值为ALWAYS。也就是说,当测试方法或类完成执行,临时目录超出范围时,JUnit框架将尝试递归地删除该目录中的所有文件和目录,最后删除临时目录本身。

如果在这个删除阶段出现问题,将抛出IOException,测试或测试类将失败。

结论

总之,在本文中,我们探讨了JUnit 5提供的TempDirectory扩展。

首先,我们从引入扩展开始,了解了使用它所需的Maven依赖项。接下来,我们从单元测试中看了几个如何使用扩展的例子。

最后,我们查看了临时文件的创建位置以及删除过程中会发生什么。

原文地址:https://www.baeldung.com/junit-5-temporary-directory

源码地址:https://github.com/eugenp/tutorials/tree/master/testing-modules/junit-5-basics

  
 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2825.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册