Перейти к основному содержимому

Поддержка временного каталога JUnit 5

· 5 мин. чтения

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 .