在Scala中,单元测试如何创建一个临时目录以用作测试的一部分?
我正在尝试对依赖于目录的类进行单元测试
class UsesDirectory(directory : java.io.File) {
...
}
我正在寻找某种形式的东西:
class UsesDirectorySpec extends FlatSpec {
val tempDir = ??? //missing piece
val usesDirectory = UsesDirectory(tempDir)
"UsesDirectory" should {
...
}
}
此外,在单元测试完成后对适当清理资源的任何评论/建议也将有所帮助。
预先感谢您的考虑和答复。
答案 0 :(得分:1)
Krzysztof的答案提供了一个很好的策略,可以避免在测试中完全不需要临时目录。
但是,如果您确实需要UsesDirectory
来处理真实文件,则可以执行以下操作来创建临时目录:
import java.nio.file.Files
val tempDir = Files.createTempDirectory("some-prefix").toFile
关于清理,您可以使用JVM shutdown钩子机制来删除临时文件。
({java.io.File
确实提供了deleteOnExit()
方法,但不适用于非空目录)
您可以使用sys.addShutdownHook {}
实现自定义的关闭挂钩,并使用Files.walk
或Files.walkTree
删除临时目录的内容。
您可能还想看看better-files library,它为常见文件操作(包括File.newTemporaryDirectory()
和file.walk()
答案 1 :(得分:0)
File
测试起来非常麻烦。没有简单的方法可以创建可用于测试的虚拟文件系统抽象。
解决这个问题的一种很酷的方法是创建某种包装,可以用于存根和模拟。
例如:
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 {
...
}
}
如果使用此方法或类似方法,则在单元测试中甚至不需要触摸文件系统。