我想编写一个读取/写入文件的单元测试,所以我制作了一个帮助器函数来制作一个临时文件(改编自Apple's docs):
func mkTmp() -> URL {
let fileManager = FileManager.default
let directory = fileManager.temporaryDirectory
let filename = UUID().uuidString
let fileURL = directory.appendingPathComponent(filename)
addTeardownBlock {
do {
if fileManager.fileExists(atPath: fileURL.path) {
try fileManager.removeItem(at: fileURL)
XCTAssertFalse(fileManager.fileExists(atPath: fileURL.path))
}
} catch {
XCTFail("Error while deleting temporary file: \(error)")
}
}
do {
try fileManager.createDirectory(at: fileURL, withIntermediateDirectories: true)
// FIXME: this always fails for some reason
XCTAssertTrue(fileManager.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)))
} catch {
XCTFail("Error while making temp dir: \(error)")
}
return fileURL
}
问题是createFile
行接近结尾。它总是失败!单元测试对临时目录没有写权限吗?
如果我忽略该失败并尝试写入文件
let file = try FileHandle(forWritingTo: mkTmp())
defer { file.closeFile() }
file.write(data)
尝试打开文件句柄时收到错误消息,指出文件不存在。
我需要在单元测试的某处设置文件写入权限吗?
答案 0 :(得分:1)
无法创建文件,因为该目录/ URL由fileManager.createDirectory(at: fileURL, ...)
创建,因此该目录已经存在。您可以通过在调用fileURL
之后添加以下断言来检查fileManager.createDirectory(at: fileURL, ...)
上存在的内容来确认这一点:
try fileManager.createDirectory(at: fileURL, withIntermediateDirectories: true)
var isDirectory: ObjCBool = false
XCTAssertTrue(fileManager.fileExists(atPath: fileURL.path, isDirectory: &isDirectory))
XCTAssertTrue(isDirectory.boolValue)
要能够在fileURL
上创建文件,您只想创建其父目录:
try fileManager.createDirectory(at: fileURL.deletingLastPathComponent(), withIntermediateDirectories: true)
答案 1 :(得分:-1)
在单元测试中创建文件时,会破坏F.I.R.S.T.原则。相反,我将以这种方式模拟文件系统的行为:
protocol FileSystemProtocol {
func createDirectory(_ url: URL) throws
func deleteDirectory(_ url: URL) throws
// readFile, writeFile etc
}
class FileSystemMock: FileSystemProtocol {
var directoryUrls = Set<URL>()
func createDirectory(_ url: URL) throws {
self.directoryUrls.insert(url)
}
func deleteDirectory(_ url: URL) throws {
self.directoryUrls.remove(url)
}
}
// setup
let fileSystemMock = FileSystemMock()
let testableObject = TestableClass(fileSystemMock)
// test testableMethod
XCTAssertNoThrow(try testableObject.testableMethod())
XCTAssert(fileSystemMock.directoryUrls.count == 1)