如何在 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.walk
或 Files.walkTree
删除临时目录的内容。
您可能还想看看 better-files library,它为包括 File.newTemporaryDirectory()
和 file.walk()
在内的常见文件操作提供了一个不太冗长的 scala API
在 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.walk
或 Files.walkTree
删除临时目录的内容。
您可能还想看看 better-files library,它为包括 File.newTemporaryDirectory()
和 file.walk()
在内的常见文件操作提供了一个不太冗长的 scala API