XCTest:在所有平台上不使用 Bundle 从磁盘加载文件(Xcode,SPM Mac/Linux)
XCTest: Load file from disk without Bundle on all platforms (Xcode, SPM Mac/Linux)
我正在寻找一种不依赖于 Bundle
.
的 XCTestCase
从磁盘加载文件的方法
Bundle
在 运行 从 Xcode(或终端上的 xcodebuild
)进行测试时效果很好,但捆绑包是 [=26= 的一部分] 项目并且对 Swift 包管理器不可用(当 运行 宁 swift test
时),既不在 Mac 也不在 Linux。
有没有一种方法可以指定在所有平台上工作的当前目录运行?或者也许有一种方法可以确定测试所在的位置,该方法也适用于所有平台?
FileManager.default.currentDirectoryPath
仅returns当前执行路径(工作目录)。
似乎当 运行 使用 Swift 包管理器 (swift test
) 进行测试时,工作目录是项目的根目录。这允许使用相对路径轻松地从磁盘加载资源(例如 ./Tests/Resources
)。
在评估了不同的选项之后,我编写了以下 class 以从测试包(如果可用)或给定路径中检索路径。
class Resource {
static var resourcePath = "./Tests/Resources"
let name: String
let type: String
init(name: String, type: String) {
self.name = name
self.type = type
}
var path: String {
guard let path: String = Bundle(for: Swift.type(of: self)).path(forResource: name, ofType: type) else {
let filename: String = type.isEmpty ? name : "\(name).\(type)"
return "\(Resource.resourcePath)/\(filename)"
}
return path
}
}
必须将资源添加到所有测试目标,以便它们在包中可用。上面的 class 可以更新以支持多个资源路径,例如通过文件扩展名。
然后可以根据需要从 XCTest
加载资源:
let file = Resource(name: "datafile", type: "csv")
let content = try String(contentsOfFile: file)
let image = try UIImage(contentsOfFile: Resource(name: "image", type: "png"))
可以将扩展添加到 Resource
以加载不同格式的内容。
extension Resource {
var content: String? {
return try? String(contentsOfFile: path).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
var base64EncodedData: Data? {
guard let string = content, let data = Data(base64Encoded: string) else {
return nil
}
return data
}
var image: Image? {
return try? UIImage(contentsOfFile: path)
}
}
并用作:
let json = Resource(name: "datafile", type: "json").contents
let image = Resource(name: "image", type: "jpeg").image
这个方法似乎对我有用,并且应该适用于 Xcode 11 和命令行。答案副本
struct Resource {
let name: String
let type: String
let url: URL
init(name: String, type: String, sourceFile: StaticString = #file) throws {
self.name = name
self.type = type
// The following assumes that your test source files are all in the same directory, and the resources are one directory down and over
// <Some folder>
// - Resources
// - <resource files>
// - <Some test source folder>
// - <test case files>
let testCaseURL = URL(fileURLWithPath: "\(sourceFile)", isDirectory: false)
let testsFolderURL = testCaseURL.deletingLastPathComponent()
let resourcesFolderURL = testsFolderURL.deletingLastPathComponent().appendingPathComponent("Resources", isDirectory: true)
self.url = resourcesFolderURL.appendingPathComponent("\(name).\(type)", isDirectory: false)
}
}
用法:
final class SPMTestDataTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(SPMTestData().text, "Hello, World!")
let file = try Resource(name: "image", type: "png")
let image = UIImage(contentsOfFile: file.url.path)
print(image)
}
}
我找到了使用的关键 #file
here
我正在寻找一种不依赖于 Bundle
.
XCTestCase
从磁盘加载文件的方法
Bundle
在 运行 从 Xcode(或终端上的 xcodebuild
)进行测试时效果很好,但捆绑包是 [=26= 的一部分] 项目并且对 Swift 包管理器不可用(当 运行 宁 swift test
时),既不在 Mac 也不在 Linux。
有没有一种方法可以指定在所有平台上工作的当前目录运行?或者也许有一种方法可以确定测试所在的位置,该方法也适用于所有平台?
FileManager.default.currentDirectoryPath
仅returns当前执行路径(工作目录)。
似乎当 运行 使用 Swift 包管理器 (swift test
) 进行测试时,工作目录是项目的根目录。这允许使用相对路径轻松地从磁盘加载资源(例如 ./Tests/Resources
)。
在评估了不同的选项之后,我编写了以下 class 以从测试包(如果可用)或给定路径中检索路径。
class Resource {
static var resourcePath = "./Tests/Resources"
let name: String
let type: String
init(name: String, type: String) {
self.name = name
self.type = type
}
var path: String {
guard let path: String = Bundle(for: Swift.type(of: self)).path(forResource: name, ofType: type) else {
let filename: String = type.isEmpty ? name : "\(name).\(type)"
return "\(Resource.resourcePath)/\(filename)"
}
return path
}
}
必须将资源添加到所有测试目标,以便它们在包中可用。上面的 class 可以更新以支持多个资源路径,例如通过文件扩展名。
然后可以根据需要从 XCTest
加载资源:
let file = Resource(name: "datafile", type: "csv")
let content = try String(contentsOfFile: file)
let image = try UIImage(contentsOfFile: Resource(name: "image", type: "png"))
可以将扩展添加到 Resource
以加载不同格式的内容。
extension Resource {
var content: String? {
return try? String(contentsOfFile: path).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
}
var base64EncodedData: Data? {
guard let string = content, let data = Data(base64Encoded: string) else {
return nil
}
return data
}
var image: Image? {
return try? UIImage(contentsOfFile: path)
}
}
并用作:
let json = Resource(name: "datafile", type: "json").contents
let image = Resource(name: "image", type: "jpeg").image
这个方法似乎对我有用,并且应该适用于 Xcode 11 和命令行。答案副本
struct Resource {
let name: String
let type: String
let url: URL
init(name: String, type: String, sourceFile: StaticString = #file) throws {
self.name = name
self.type = type
// The following assumes that your test source files are all in the same directory, and the resources are one directory down and over
// <Some folder>
// - Resources
// - <resource files>
// - <Some test source folder>
// - <test case files>
let testCaseURL = URL(fileURLWithPath: "\(sourceFile)", isDirectory: false)
let testsFolderURL = testCaseURL.deletingLastPathComponent()
let resourcesFolderURL = testsFolderURL.deletingLastPathComponent().appendingPathComponent("Resources", isDirectory: true)
self.url = resourcesFolderURL.appendingPathComponent("\(name).\(type)", isDirectory: false)
}
}
用法:
final class SPMTestDataTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(SPMTestData().text, "Hello, World!")
let file = try Resource(name: "image", type: "png")
let image = UIImage(contentsOfFile: file.url.path)
print(image)
}
}
我找到了使用的关键 #file
here