一个 Swift 实现:
Swift 2
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)
Swift 3, Swift 4
let testBundle = Bundle(for: type(of: self))
let filePath = testBundle.path(forResource: "imageName", ofType: "png")
XCTAssertNotNil(filePath)
Bundle提供了发现配置的主要路径和测试路径的方法:
@testable import Example
class ExampleTests: XCTestCase {
func testExample() {
let bundleMain = Bundle.main
let bundleDoingTest = Bundle(for: type(of: self ))
let bundleBeingTested = Bundle(identifier: "com.example.Example")!
print("bundleMain.bundlePath : \(bundleMain.bundlePath)")
print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)")
print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)")
print("bundleMain = " + bundleMain.description)
print("bundleDoingTest = " + bundleDoingTest.description)
print("bundleUnderTest = " + bundleBeingTested.description)
在Xcode 6|7|8|9中,一个
单元测试包路径将会在
Developer/Xcode/DerivedData
中,类似于...
/Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
foo.txt
...这与
Developer/CoreSimulator/Devices
中的
常规(非单元测试)捆绑路径是分开的。
/Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
请注意,默认情况下,单元测试可执行文件与应用程序代码链接在一起。然而,单元测试代码应该仅在测试包中具有目标成员资格。应用程序代码应仅在应用程序包中具有目标成员资格。在运行时,单元测试目标包会被注入到应用程序包中进行执行。
Swift Package Manager (SPM) 4:
let testBundle = Bundle(for: type(of: self))
print("testBundle.bundlePath = \(testBundle.bundlePath) ")
注意:默认情况下,命令行
swift test
将创建一个名为
MyProjectPackageTests.xctest
的测试包。而
swift package generate-xcodeproj
将创建一个名为
MyProjectTests.xctest
的测试包。这些不同的测试包有
不同的路径。
此外,不同的测试包可能具有一些内部目录结构和内容差异。
无论哪种情况,.bundlePath
和.bundleURL
都将返回当前在macOS上运行的测试包的路径。然而,在Ubuntu Linux上,Bundle
目前尚未实现。
此外,命令行swift build
和swift test
目前没有提供复制资源的机制。
然而,只要付出一些努力,就有可能在macOS的Xcode、macOS命令行和Ubuntu命令行环境中建立使用Swift Package Manager的流程。一个示例可以在这里找到:
004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref。
另请参阅:
使用Swift Package Manager在单元测试中使用资源。
Swift Package Manager(SwiftPM)5.3+
Swift 5.3包括Package Manager Resources SE-0271演进提案,状态为“已实施(Swift 5.3)”。:-)
资源并不总是为软件包的客户端使用而设计;其中一种资源的用途可能是仅供单元测试所需的测试固件。这些资源不会与库代码一起添加到软件包的客户端中,只会在运行软件包的测试时使用。
在`target`和`testTarget`的API中添加一个新的`resources`参数,以允许显式声明资源文件。
SwiftPM使用文件系统约定来确定每个软件包中属于每个目标的源文件集:具体来说,目标的源文件是那些位于目标的指定“目标目录”下的文件。默认情况下,这是一个与目标同名并位于“Sources”(对于常规目标)或“Tests”(对于测试目标)的目录,但此位置可以在软件包清单中进行自定义设置。
let path = Bundle.module.path(forResource: "DefaultSettings", ofType: "plist")
let image = UIImage(named: "MyIcon", in: Bundle.module, compatibleWith: UITraitCollection(userInterfaceStyle: .dark))
let shader = try mtlDevice.makeDefaultLibrary(bundle: Bundle.module).makeFunction(name: "vertexShader")
let texture = MTKTextureLoader(device: mtlDevice).newTexture(name: "Grass", scaleFactor: 1.0, bundle: Bundle.module, options: options)
例子
import PackageDescription
targets: [
.target(
name: "CLIQuickstartLib",
dependencies: [],
resources: [
.process("Resources"),
]),
.testTarget(
name: "CLIQuickstartLibTests",
dependencies: [],
resources: [
.copy("Resources"),
]),
当前问题
Xcode
Bundle.module
是由SwiftPM生成的(参见Build/BuildPlan.swift SwiftTargetBuildDescription generateResourceAccessor()),因此在Xcode构建时不会出现在Foundation.Bundle中。
在Xcode中,一个类似的方法是手动添加一个
Resources
引用文件夹到模块中,然后添加一个Xcode构建阶段
copy
来将
Resource
放入某个
*.bundle
目录,并且添加一个
#ifdef Xcode
编译指令以便Xcode构建可以使用这些资源。
#if Xcode
extension Foundation.Bundle {
static var module: Bundle = {
var thisModuleName = "CLIQuickstartLib"
var url = Bundle.main.bundleURL
for bundle in Bundle.allBundles
where bundle.bundlePath.hasSuffix(".xctest") {
url = bundle.bundleURL.deletingLastPathComponent()
thisModuleName = thisModuleName.appending("Tests")
}
url = url.appendingPathComponent("\(thisModuleName).bundle")
guard let bundle = Bundle(url: url) else {
fatalError("Bundle.module could not load: \(url.path)")
}
return bundle
}()
static var moduleDir: URL = {
var url = Bundle.main.bundleURL
for bundle in Bundle.allBundles
where bundle.bundlePath.hasSuffix(".xctest") {
url = bundle.bundleURL.deletingLastPathComponent()
}
return url
}()
}
#endif
self
指的是主包中的一个类,而不是测试用例类。请将[self class]
替换为主包中的任何一个类。我会编辑我的示例。 - benzadobundleForClass:
和单元测试包中的一个类。您应该在单元测试代码中获取文件的路径,然后将路径字符串传递给其他代码。 - benzado