如何在 Scala 单元测试中创建临时目录

How To Create Temporary Directory in Scala Unit Tests

在 Scala 中,单元测试如何创建临时目录以用作测试的一部分?

我正在尝试对依赖于目录的 class 进行单元测试

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

我正在寻找以下形式的内容:

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

  val usesDirectory = UsesDirectory(tempDir)

  "UsesDirectory" should {
    ...
  }
}

此外,任何关于在单元测试完成后适当清理资源的 comments/suggestions 都会有所帮助。

提前感谢您的考虑和回复。

File in 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)
  }
}

那么你必须在 class:

中使用它而不是 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 {
      ...
    }
}

如果您使用这种或类似的方法,您甚至不需要在单元测试中接触文件系统。

Krzysztof 的回答提供了一个很好的策略来避免在测试中完全需要临​​时目录。

然而,如果您确实需要 UsesDirectory 来处理真实文件,您可以像下面这样创建一个临时目录:

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

关于清理,您可以使用 JVM 关闭挂钩机制来删除您的临时文件。

java.io.File 确实提供了 deleteOnExit() 方法,但它不适用于非空目录)

您可以使用 sys.addShutdownHook {} 实现自定义关闭挂钩,并使用 Files.walkFiles.walkTree 删除临时目录的内容。

您可能还想看看 better-files library,它为包括 File.newTemporaryDirectory()file.walk() 在内的常见文件操作提供了一个不太冗长的 scala API