为什么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目标。

在这里输入图像描述