Как создать временный каталог в модульных тестах Scala - PullRequest
0 голосов
/ 01 марта 2019

Как в модуле scala можно создать временный каталог для использования во время тестирования?

Я пытаюсь выполнить модульное тестирование класса, который зависит от каталога

class UsesDirectory(directory : java.io.File) {
  ...
}

Я ищу что-то в форме:

class UsesDirectorySpec extends FlatSpec {
  val tempDir = ??? //missing piece

  val usesDirectory = UsesDirectory(tempDir)

  "UsesDirectory" should {
    ...
  }
}

Кроме того, любые комментарии / предложения по надлежащей очистке ресурса после завершения модульного тестирования будут полезны.

Заранее благодарим за внимание и ответ.

Ответы [ 2 ]

0 голосов
/ 03 марта 2019

Ответ Кшиштофа дает хорошую стратегию, позволяющую полностью избежать временных каталогов в ваших тестах.

Однако, если вам нужно UsesDirectory для работы с реальными файлами, вы можете сделать что-то вроде следующего для созданиявременный каталог:

import java.nio.file.Files
val tempDir = Files.createTempDirectory("some-prefix").toFile

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

(java.io.File предоставляет метод deleteOnExit(), но он не 'работа с непустыми каталогами)

Вы можете реализовать пользовательский хук отключения, используя sys.addShutdownHook {}, и использовать Files.walk или Files.walkTree, чтобы удалить содержимое вашего временного каталога.

Также вы можете взглянуть на библиотеку улучшенных файлов , которая предоставляет менее подробный API-интерфейс scala для операций с общими файлами, включая File.newTemporaryDirectory() и file.walk()

0 голосов
/ 02 марта 2019

File в Java очень громоздко для тестирования.Не существует простого способа создания какой-либо виртуальной абстракции файловой системы, которую можно использовать для тестов.

Крутой способ обойти это - создать какую-то оболочку, которую можно использовать для создания заглушек и насмешек.

Например:

trait FileOps { //trait which works as proxy for file
  def getName(): String
  def exists(): Boolean
}

object FileOps {

  class FileOpsImpl(file: File) extends FileOps {
    override def getName(): String = file.getName //delegate all methods you need
    override def exists(): Boolean = file.exists()
  }

  implicit class FromFile(file: File) { //implicit method to convert File to FileOps
    def toFileOps: FileOpsImpl = new FileOpsImpl(file)
  }
}

Тогда вам придется использовать его вместо File в вашем классе:

class UsesDirectory(directory : FileOps) {
  ...
}

//maybe you can even create implicit conversion, but it's better to do it explicitly
val directory = new UserDirectory(file.toFileOps) 

И в чем выгода?

В своих тестах вы можете предоставить пользовательскую реализацию FileOps:

class UsesDirectorySpec extends FlatSpec {
    val dummyFileOps = new FileOps {
        override def getName(): String = "mock"
        override def exists(): Boolean = true
    }

    //OR

    val mockFileOps = mock[FileOps] //you can mock it easily since it's only trait

    val usesDirectory = UsesDirectory(dummyFileOps)

    "UsesDirectory" should {
      ...
    }
}

Если вы используете этот или аналогичный подход, вам даже не нужно трогать файловую систему в модульном тесте.

...