Как правильно записать временный файл во время модульных тестов с Maven?

Я написал модульный тест, который записывает файл в файловую систему, без указания пути, по которому он пишет в рабочий каталог; поэтому, если выполняется из каталога проекта, он записывает в корневой каталог проекта, если в родительском каталоге проектов он записывает в корневой каталог родителей.

Так каков правильный способ записи в целевой каталог? Вполне возможно, каталог внутри целевого каталога?

Если я просто укажу target/ с файлом он будет записывать в родительские цели проектов вместо целей проектов.

ОБНОВЛЕНИЕ: я на самом деле хочу файл после завершения теста. Файл предназначен для формата извлечения для третьих сторон, который необходимо отправить третьим лицам. Тест можно включить / выключить, чтобы разрешить запуск только в том случае, если формат файла изменяется для повторного утверждения. Это не большая проблема, где файл идет, но я хотел бы что-то, что легко найти.

8 ответов

Решение

Вы можете попробовать использовать TemporaryFolder JUnit @Rule, как описано здесь

TemporaryFolder создает папку в каталоге временных файлов по умолчанию, указанном системным свойством java.io.tmpdir. Метод newFile создает новый файл во временном каталоге, а newFolder создает новую папку.

Когда тестовый метод заканчивается, JUnit автоматически удаляет все файлы и каталоги, включая TemporaryFolder. JUnit гарантирует удаление ресурсов, независимо от того, пройден тест или нет.


После обновления вопроса

Вы можете изменить рабочий каталог, используемый maven-surefire-plugin,

<plugins>
    [...]
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.12.3</version>
        <configuration>
          <workingDirectory>${project.build.directory}</workingDirectory>
        </configuration>
      </plugin>
    [...]
</plugins>

Вы можете изменить этот рабочий каталог на что угодно для ваших тестов, например ${project.build.directory}/my_special_dir/,

Рабочий каталог в плагине surefire влияет только на выполняемые тесты и ТОЛЬКО на тесты, проводимые maven. Если вы запускаете свои тесты из среды IDE, рабочий каталог будет чем-то другим.

Не нужно изобретать велосипед...

JDK предоставляет способ создания временного файла и способ его автоматического удаления при выходе:

File file = File.createTempFile( "some-prefix", "some-ext");
file.deleteOnExit();

Используйте файл, и он будет автоматически удален после завершения теста. Это все, что нужно сделать.

Чтобы указать каталог для временных файлов, используйте перегруженный метод:

File file = File.createTempFile( "prefix", "ext", new File("/some/dir/path"));

Начиная с JUnit 5 вы можете использовать @TempDir . Он будет удален (включая его содержимое) после тестирования.

либо один временный каталог для каждого теста:

      @Test
void testWithTempFiles(@TempDir Path tempDir) 
    Path file = dir.resolve("temp_file.txt");
    ...
}

или один для всех тестов в классе:

      @TempDir
static Path tempDir

@Test
void testWithTempFiles() 
    Path file = dir.resolve("temp_file.txt");
    ...
}

Чтобы заявить об этом заранее, я категорически против делать такие вещи в модульном тестировании. Я действительно не пробовал это, но это должно работать:

Предположим, вы используете плагин surefire, из документа, который он цитировал, вы можете получить доступ к базовому каталогу тестируемого проекта с помощью System.getProperty("basedir"), Получите его и создайте файлы в basedir / target.

Более "подходящий" способ (поскольку у нас может быть шанс, что мы настроили выходной каталог на что-то другое, вы можете изменить конфигурацию плагина surefire на что-то вроде этого:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <systemPropertyVariables>
            <myOutDir>${project.build.outputDirectory}</myOutDir>
        </systemPropertyVariables>
    </configuration>
</plugin>

Тогда вы можете получить фактический выходной каталог по System.getProperty("myOutDir") в вашем тесте.

Я написал бы подпрограмму, которая определяет, куда файл должен быть записан, и который я потом использую, в общем, я стараюсь избегать (насколько это возможно) доступа к постоянным данным в юнит-тестах, таких как файловый ввод-вывод или доступ к базе данных, это имеет соображения производительности и другие тоже,

Посмотрите на этот ответ: /questions/46370608/modulnoe-testirovanie-fajlov-vvoda-vyivoda/46370702#46370702

Вы захотите иметь возможность запускать свои тесты как из IDE, так и из Maven, поэтому лучше всего писать свои тесты, чтобы они не предполагали, что они выполняются в Maven.

Одним из лучших способов работы с временными файлами является использование правил junit. Это позволяет вам полагаться на правило для очистки для вас.

Временные файлы должны быть созданы во временный каталог. Получить его с помощью вызова System.getProperty("java.io.tmpdir")

Временный файл должен быть временным, т.е. должен быть удален, когда он не нужен. Чтобы добиться этого, не забудьте удалить его в finally блок или код, который запускается после теста, то есть:

File tmpFile = ...
try {
   // deal with tempFile
} finally {
    tempFile.delete();
}

и / или

public class MyTestCase {
    private File tmpFile = null;

    @Before
    public void setUp() {
        tmpFile = ...;
    }

    @Test
    public void setUp() {
        // deal with tmpFile
    }

    @After
    public void setUp() {
        tmpFile.delete();
    }
}

использование File.createTempFile(String prefix, String suffix) если это возможно, то есть вы можете использовать файл со специальным именем, созданным createTempFile(),

использование file.deleteOnExit(), Это создает ловушку, которая автоматически удаляет файл, когда JVM завершается. Файл останется, только если JVM была убита kill -9, так что у него не было возможности запустить код завершения работы.

Вот несколько способов использования JUnit 5 и языка Kotlin.

  • Использование JUnit 5 в поле:

            @TempDir(cleanup = ON_SUCCESS)
    lateinit var tempDirectory: Path
    
    @Test fun example() {
        // use the tempDirectory
    }
    
  • Использование JUnit 5@TempDirпо параметру тестовой функции:

            @Test fun example(
        @TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDirectory: Path
    ) {
        // use the tempDirectory
    }
    
  • Создание файла вручную и вызовdeleteOnExit():

            @Test fun example() {
        val file = File("file.txt").apply { deleteOnExit() }
    }
    
  • Использование КотлинаcreateTempDirectoryиcreateTempFileфункции в тестовом классе или тестовой функции:

            val file = createTempFile("file.txt")
    
Другие вопросы по тегам