为什么unit testing内部的代码不能findbundle资源?
我unit testing的一些代码需要加载一个资源文件。 它包含以下行:
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
在应用程序中它运行得很好,但是当由unit testing框架pathForResource:
运行时pathForResource:
返回nil,这意味着它找不到foo.txt
。
我已经确定foo.txt
包含在unit testing目标的Copy Bundle Resources构build阶段,所以为什么找不到这个文件呢?
当unit testing工具运行你的代码时,你的unit testing包不是主包。
即使你正在运行testing,而不是你的应用程序,你的应用程序包仍然是主要的包。 (可能这会阻止你正在testing的代码search错误的包)。因此,如果你添加一个资源文件到unit testing包,如果search主包,你将不会find它。 如果您将以上行replace为:
NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *path = [bundle pathForResource:@"foo" ofType:@"txt"];
然后你的代码将search你的unit testing类所在的包,一切都会好的。
Swift实现:
Swift 2
let testBundle = NSBundle(forClass: self.dynamicType) let fileURL = testBundle.URLForResource("imageName", withExtension: "png") XCTAssertNotNil(fileURL)
Swift 3
let testBundle = Bundle(for: type(of: self)) let filePath = testBundle.path(forResource: "imageName", ofType: "png") XCTAssertNotNil(filePath)
Bundle提供了发现configuration的主要path和testingpath的方法:
@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)") // …/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents print("bundleDoingTest.bundlePath : \(bundleDoingTest.bundlePath)") // …/PATH/TO/Debug/ExampleTests.xctest print("bundleBeingTested.bundlePath : \(bundleBeingTested.bundlePath)") // …/PATH/TO/Debug/Example.app print("bundleMain = " + bundleMain.description) // Xcode Test Agent print("bundleDoingTest = " + bundleDoingTest.description) // Test Case Bundle print("bundleUnderTest = " + bundleBeingTested.description) // App Bundle
在Xcode 6 | 7 | 8中, unit testing捆绑包path将在Developer/Xcode/DerivedData
,如…
/Users/ UserName/ Library/ Developer/ Xcode/ DerivedData/ App-qwertyuiop.../ Build/ Products/ Debug-iphonesimulator/ AppTests.xctest/ foo.txt
…与Developer/CoreSimulator/Devices
常规(非unit testing)捆绑包path分开:
/Users/ UserName/ Library/ Developer/ CoreSimulator/ Devices/ _UUID_/ data/ Containers/ Bundle/ Application/ _UUID_/ App.app/
另请注意,unit testing可执行文件默认情况下与应用程序代码链接。 但是,unit testing代码只能在testing包中拥有目标成员资格。 应用程序代码应该只在应用程序包中具有目标成员资格。 在运行时,unit testing目标包被注入到应用程序包中执行 。
使用Swift Swift 3,语法self.dynamicType
已被弃用,请使用它
let testBundle = Bundle(for: type(of: self)) let fooTxtPath = testBundle.path(forResource: "foo", ofType: "txt")
要么
let fooTxtURL = testBundle.url(forResource: "foo", withExtension: "txt")
确认资源已添加到testing目标。