1. Обзор
При тестировании нам часто требуется доступ к временному файлу. Однако самостоятельно управлять созданием и удалением этих файлов может быть обременительно.
В этом кратком руководстве мы рассмотрим, как JUnit 5 облегчает это, предоставляя расширение TempDirectory .
Чтобы получить подробное руководство по тестированию с помощью JUnit, ознакомьтесь с нашим превосходным руководством по JUnit 5 .
2. Расширение TempDirectory
Начиная с версии 5.4.2, JUnit 5 предоставляет расширение TempDirectory. Однако важно отметить, что официально это по-прежнему экспериментальная функция, и нам рекомендуется давать отзывы команде JUnit.
Как мы увидим позже, мы можем использовать это расширение для создания и очистки временного каталога для отдельного теста или всех тестов в тестовом классе .
Обычно при использовании расширения нам нужно зарегистрировать его из теста JUnit 5, используя аннотацию @ExtendWith
. Но в этом нет необходимости с расширением TempDirectory, которое встроено и зарегистрировано по умолчанию.
3. Зависимости Maven
Прежде всего, давайте добавим зависимости проекта, которые нам понадобятся для наших примеров.
Помимо основной библиотеки 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>
Как всегда, последнюю версию мы можем получить с Maven Central .
В дополнение к этому нам также нужно добавить зависимость junit-jupiter-params
:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
Снова последнюю версию мы можем найти в Maven Central .
4. Использование аннотации @TempDir
Чтобы использовать расширение TempDirectory, нам нужно использовать аннотацию @TempDir
. Мы можем использовать эту аннотацию только со следующими двумя типами:
java.nio.file.Path
java.io.Файл
На самом деле, если мы попытаемся использовать его с другим типом, будет выброшено исключение org.junit.jupiter.api.extension.ParameterResolutionException .
Далее давайте рассмотрим несколько различных способов использования этой аннотации.
4.1. @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)));
}
Как мы видим, наш тестовый метод создает и записывает файл с именем number.txt
во временный каталог tempDir
.
Затем мы проверяем, что файл существует и что содержимое соответствует тому, что было написано изначально. Действительно красиво и просто!
4.2. @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
для нашего временного каталога. Снова пишем несколько строк и проверяем, что они были написаны успешно.
Если бы мы затем снова использовали эту единственную ссылку в других методах тестирования, каждый тест использовал бы свой собственный временный каталог .
4.3. Общий временный каталог
Иногда нам может понадобиться разделить временный каталог между тестовыми методами .
Мы можем сделать это, объявив наше поле статическим
:
@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));
}
Ключевым моментом здесь является то, что мы используем статическое поле sharedTempDir
, которое мы разделяем между двумя методами тестирования .
В первом тесте мы снова записываем несколько строк в файл с именем number.txt
. Затем мы проверяем, что файл и контент уже существуют в следующем тесте.
Мы также применяем порядок тестов с помощью аннотации @Order
, чтобы гарантировать неизменное поведение.
5. Гочки
Теперь давайте рассмотрим некоторые тонкости, о которых следует знать при работе с расширением TempDirectory.
5.1. Творчество
Любознательный читатель, скорее всего, задастся вопросом, где на самом деле создаются эти временные файлы?
Ну, внутренне класс 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
.
5.2. Удаление
Когда тестовый метод или класс завершит выполнение и временный каталог выйдет за пределы области видимости, среда JUnit попытается рекурсивно удалить все файлы и каталоги в этом каталоге и, наконец, сам временный каталог.
Если на этом этапе удаления возникает проблема, будет выдано исключение IOException
, и тест или тестовый класс завершится ошибкой.
6. Заключение
Подводя итог, в этом руководстве мы изучили расширение TempDirectory, предоставляемое JUnit 5.
Во-первых, мы начали с представления расширения и узнали, какие зависимости Maven нам нужны для его использования. Далее мы рассмотрели несколько примеров использования расширения в наших модульных тестах.
Наконец, мы рассмотрели несколько ошибок, включая то, где создаются временные файлы и что происходит во время удаления.
Как всегда, полный исходный код статьи доступен на GitHub .