Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Временные файлы: @TempDir

Код, который работает с файлами, неудобно тестировать: куда писать, как убирать за собой, что будет, если два теста одновременно пишут один файл? JUnit решает это аннотацией @TempDir. Перед тестом он создаёт пустую временную папку, передаёт тесту её путь, а после теста удаляет её со всем содержимым.

Тестируемый класс

Блог выгружает посты в CSV-файл. Создайте src/main/java/com/example/blog/PostExporter.java:

// src/main/java/com/example/blog/PostExporter.java
package com.example.blog;
 
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
 
public class PostExporter {
 
    public void exportCsv(List<Post> posts, Path file) throws IOException {
        List<String> lines = posts.stream()
                .map(p -> p.id() + ";" + p.title() + ";" + p.author())
                .toList();
        Files.write(file, lines);
    }
}

Метод получает путь к файлу параметром — именно это делает его удобным для тестов: куда писать, решает тест.

@TempDir на поле

// src/test/java/com/example/blog/PostExporterTest.java
package com.example.blog;
 
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
 
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
 
import static org.junit.jupiter.api.Assertions.assertEquals;
 
class PostExporterTest {
 
    @TempDir
    Path dir;
 
    @Test
    void writesOneLinePerPost() throws IOException {
        Path file = dir.resolve("posts.csv");
        List<Post> posts = List.of(
                new Post(1L, "Привет, JUnit", "anna", true),
                new Post(2L, "Основы Mockito", "oleg", false)
        );
 
        new PostExporter().exportCsv(posts, file);
 
        assertEquals(List.of("1;Привет, JUnit;anna", "2;Основы Mockito;oleg"),
                Files.readAllLines(file));
    }
}

dir — свежая пустая папка для каждого теста где-то во временном каталоге системы. dir.resolve("posts.csv") строит путь к файлу внутри неё. Тест пишет файл, читает его обратно и сравнивает строки. Files.write и Files.readAllLines по умолчанию используют UTF-8, поэтому русский текст не портится. Тестовый метод может объявить throws IOException — неожиданное исключение просто уронит тест.

@TempDir на параметре

Папку можно запросить и параметром теста:

// src/test/java/com/example/blog/PostExporterTest.java
@Test
void emptyListGivesEmptyFile(@TempDir Path other) throws IOException {
    Path file = other.resolve("empty.csv");
 
    new PostExporter().exportCsv(List.of(), file);
 
    assertEquals(0, Files.size(file));
}

Это удобно, когда файлы нужны только одному тесту класса.

Почему не просто «C:/tmp»

Фиксированный путь@TempDir
Работает только на машине, где есть эта папкаРаботает везде: Windows, Linux, CI
Файлы от прошлого запуска могут повлиять на результатКаждый тест начинает с пустой папки
Два теста, запущенные параллельно, перезаписывают друг другаУ каждого теста своя папка
Мусор остаётся на дискеПапка удаляется после теста

Если после падения нужно посмотреть на файл, напишите @TempDir(cleanup = CleanupMode.ON_SUCCESS): папка останется, только когда тест упал.

Частая ошибка

@TempDir работает только с java.nio.file.Path и java.io.File. Поле типа String — ошибка конфигурации:

@TempDir
String dir;
org.junit.jupiter.api.extension.ExtensionConfigurationException: Can only resolve @TempDir field of type java.nio.file.Path or java.io.File but was: java.lang.String

Объявите поле как Path. Если нужна строка, вызовите dir.toString().

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.