1. Overview
1.概述
When testing, we often need access to a temporary file. However, managing the creation and deletion of these files ourselves can be cumbersome.
在测试时,我们经常需要访问一个临时文件。然而,自己管理这些文件的创建和删除可能是很麻烦的。
In this quick tutorial, we’ll take a look at how JUnit 5 alleviates this by providing the TempDirectory extension.
在这个快速教程中,我们将看看JUnit 5如何通过提供TempDirectory扩展来缓解这一问题。
For an in-depth guide to testing with JUnit, check out our excellent Guide to JUnit 5.
有关使用JUnit进行测试的深入指南,请查看我们优秀的JUnit 5指南。
2. The TempDirectory Extension
2.TempDirectory扩展
Starting with version 5.4.2, JUnit 5 provides the TempDirectory Extension. However, it’s important to note that officially this is still an experimental feature and that we’re encouraged to give feedback to the JUnit team.
从 5.4.2 版开始,JUnit 5 提供了 TempDirectory 扩展。然而,需要注意的是,在官方看来,这仍然是一个实验性功能,我们被鼓励向JUnit团队提供反馈。
As we’ll see later, we can use this extension to create and clean up a temporary directory for an individual test or all tests in a test class.
正如我们稍后看到的,我们可以使用这个扩展来创建和清理一个单独的测试或一个测试类的所有测试的临时目录。
Normally when using an extension, we need to register it from within a JUnit 5 test using the @ExtendWith annotation. But this is not necessary with the TempDirectory extension which is built-in and registered by default.
通常,当使用扩展时,我们需要在JUnit 5测试中使用@ExtendWith注解来注册它。但对于内置并默认注册的TempDirectory扩展来说,这是没有必要的。
3. Maven Dependencies
3.Maven的依赖性
First of all, let’s add the project dependencies we will need for our examples.
首先,让我们添加我们的例子需要的项目依赖。
Apart from the main JUnit 5 library junit-jupiter-engine we’ll also need the junit-jupiter-api library:
除了主要的JUnit 5库junit-jupiter-engine,我们还需要junit-jupiter-api库。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
As always, we can get the latest version from Maven Central.
一如既往,我们可以从Maven中心获得最新版本。
In addition to this, we’ll also need to add the junit-jupiter-params dependency:
除此之外,我们还需要添加junit-jupiter-params依赖项。
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
Again we can find the latest version in Maven Central.
同样,我们可以在Maven中心找到最新版本。
4. Using the @TempDir Annotation
4.使用@TempDir注释
In order to use the TempDirectory extension, we need to make use of the @TempDir annotation. We can only use this annotation with the following two types:
为了使用TempDirectory扩展,我们需要利用@TempDir注解。我们只能在以下两种类型中使用这个注解。
- java.nio.file.Path
- java.io.File
In fact, if we try to use it with a different type, then an org.junit.jupiter.api.extension.ParameterResolutionException will be thrown.
事实上,如果我们试图用不同的类型来使用它,那么就会抛出org.junit.jupiter.api.extension.ParameterResolutionException。
Next, let’s explore several different ways of using this annotation.
接下来,让我们探讨一下使用这种注释的几种不同方式。
4.1. @TempDir as a Method Parameter
4.1.@TempDir作为一个方法参数
Let’s begin by seeing how to inject a parameter annotated with @TempDir into a single test method:
让我们首先看看如何将一个注有@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)));
}
As we can see, our test method creates and writes a file called numbers.txt in the temporary directory tempDir.
我们可以看到,我们的测试方法在临时目录tempDir中创建并写入一个名为numbers.txt的文件。
We then check that the file exists and that the content matches what was originally written. Really nice and simple!
然后我们检查该文件是否存在,内容是否与最初写的内容一致。真的很好,很简单!
4.2. @TempDir on an Instance Field
4.2.@TempDir在实例字段上
In this next example, we’ll annotate a field in our test class using the @TempDir annotation:
在接下来的例子中,我们将使用@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())));
}
This time, we use a java.io.File for our temporary directory. Again, we write some lines and check they were written successfully.
这一次,我们使用一个java.io.File作为我们的临时目录。再次,我们写一些行,并检查它们是否被成功写入。
If we were to then use this single reference again in other test methods, each test would use its own temporary directory.
如果我们随后在其他测试方法中再次使用这个单一的引用,每个测试都会使用自己的临时目录。
4.3. A Shared Temporary Directory
4.3.一个共享的临时目录
Sometimes, we might want to share a temporary directory between test methods.
有时,我们可能想在测试方法之间共享一个临时目录。
We can do this by declaring our field static:
我们可以通过声明我们的字段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));
}
The key point here is that we use a static field sharedTempDir which we share between the two test methods.
这里的关键点是,我们使用一个静态字段sharedTempDir,我们在两个测试方法之间共享。
In the first test, we again write some lines to a file called numbers.txt. Then we check that the file and content already exist in the next test.
在第一个测试中,我们再次写一些行到一个叫做numbers.txt的文件。然后我们在下一个测试中检查该文件和内容是否已经存在。
We also enforce the order of the tests via the @Order annotation to make sure the behavior is always consistent.
我们还通过@Order注解强制执行测试的顺序,以确保行为始终一致。
5. Gotchas
5.弊端
Now let’s review some of the subtleties we should be aware of when working with the TempDirectory extension.
现在让我们回顾一下在使用TempDirectory扩展时我们应该注意的一些微妙之处。
5.1. Creation
5.1.创造
The curious reader out there will most probably be wondering where these temporary files are actually created?
好奇的读者很可能会想知道这些临时文件究竟是在哪里创建的?
Well, internally the JUnit TemporaryDirectory class makes use of the Files.createTempDirectory(String prefix) method. Likewise, this method then makes use of the default system temporary file directory.
那么,在内部,JUnit的TemporaryDirectory类利用了Files.createTempDirectory(String prefix)方法。同样地,这个方法然后利用了默认的系统临时文件目录。
This is normally specified in the environment variable TMPDIR:
这通常在环境变量TMPDIR中指定。
TMPDIR=/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/
For instance, resulting in a temporary file location:
例如,导致一个临时文件的位置。
/var/folders/3b/rp7016xn6fz9g0yf5_nj71m00000gn/T/junit5416670701666180307/numbers.txt
Meanwhile, if the temporary directory cannot be created, an ExtensionConfigurationException will be thrown as appropriate. Or as previously mentioned, a ParameterResolutionException.
同时,如果不能创建临时目录,将酌情抛出一个ExtensionConfigurationException。或者如前所述,一个ParameterResolutionException。
5.2. Deletion
5.2.删除
When the test method or class has finished execution and the temporary directory goes out of scope, the JUnit framework will attempt to recursively delete all files and directories in that directory and, finally, the temporary directory itself.
当测试方法或类执行完毕,临时目录超出范围时,JUnit框架将尝试递归删除该目录中的所有文件和目录,最后是临时目录本身。
If there is a problem during this deletion phase, an IOException will be thrown and the test or test class will fail.
如果在这个删除阶段出现问题,将抛出一个IOException,测试或测试类将失败。
6. Conclusion
6.结论
To summarize, in this tutorial, we’ve explored the TempDirectory Extension provided by JUnit 5.
总结一下,在本教程中,我们已经探讨了JUnit 5提供的TempDirectory扩展。
First, we started by introducing the extension and learned what Maven dependencies we need in order to use it. Next, we looked at several examples of how to use the extension from within our unit tests.
首先,我们从介绍扩展开始,了解了使用该扩展需要哪些Maven依赖项。接下来,我们看了几个如何在单元测试中使用该扩展的例子。
Finally, we looked at several gotchas including where the temporary files are created and what happens during deletion.
最后,我们看了几个问题,包括临时文件是在哪里创建的,以及在删除时发生了什么。
As always, the full source code of the article is available over on GitHub.
一如既往,文章的完整源代码可在GitHub上获得over。