我正在尝试使用TDD和新的XCTest框架编写iOS应用程序。我的一个方法从Internet检索文件(给定NSURL对象)并将其存储在用户的文档中。该方法的签名类似于:
- (void) fetchAndStoreImage:(NSURL *)imageUrl
我正在尝试为这种方法编写测试,如果没有连接到互联网就不会失败。我的方法(取自之前的question)是使用NSURL将方法调用到本地文件系统中的图像。
当创建启用了单元测试的新项目时,Tests目录有一个名为“Supporting Files”的子目录。我想这是我的测试图像应该去的地方。我的问题是如何获得指向此目录中的图像的NSURL对象,因为我不希望测试图像与应用程序捆绑在一起。任何帮助表示赞赏。
答案 0 :(得分:120)
事实上,运行UnitTest时[NSBundle mainBundle]
不是您应用的路径,但是/ Developer / usr / bin,所以这不起作用。
在单元测试中获取资源的方法如下:OCUnit & NSBundle
简而言之,请使用:
[[NSBundle bundleForClass:[self class]] resourcePath]
或在你的情况下:
[[NSBundle bundleForClass:[self class]] resourceURL]
答案 1 :(得分:38)
Swift 2:
let testBundle = NSBundle(forClass: self.dynamicType)
let fileURL = testBundle.URLForResource("imageName", withExtension: "png")
XCTAssertNotNil(fileURL)
斯威夫特3,4:
let testBundle = Bundle(for: type(of: self))
let fileURL = testBundle.url(forResource: "imageName", withExtension: "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)")
// …/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网址将在Developer/Xcode/DerivedData
类似......
file:///Users/
UserName/
Library/
Developer/
Xcode/
DerivedData/
App-qwertyuiop.../
Build/
Products/
Debug-iphonesimulator/
AppTests.xctest/
imageName.png
...与Developer/CoreSimulator/Devices
网址
file:///Users/
UserName/
Library/
Developer/
CoreSimulator/
Devices/
_UUID_/
data/
Containers/
Bundle/
Application/
_UUID_/
App.app/
另请注意,单元测试可执行文件默认情况下与应用程序代码链接。但是,单元测试代码应仅在测试包中具有目标成员资格。应用程序代码应仅在应用程序包中具有目标成员身份。在运行时,单元测试目标包为injected into the application bundle for execution。
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实现Bundle
。
此外,命令行swift build
和swift test
目前不提供复制资源的机制。
但是,通过一些努力,可以设置使用Swift包管理器的进程以及macOS Xcode,macOS命令行和Ubuntu命令行环境中的资源。可以在此处找到一个示例:004.4'2 SW Dev Swift Package Manager (SPM) With Resources Qref
Swift Package Manager(SPM)4.2
Swift Package Manager PackageDescription 4.2引入了对local dependencies的支持。
本地依赖项是磁盘上的程序包,可以使用它们的路径直接引用。仅在根包中允许本地依赖,并且它们将覆盖包图中具有相同名称的所有依赖项。
注意:我希望,但尚未测试,SPM 4.2应该可以使用以下内容:
// swift-tools-version:4.2
import PackageDescription
let package = Package(
name: "MyPackageTestResources",
dependencies: [
.package(path: "../test-resources"),
],
targets: [
// ...
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage", "MyPackageTestResources"]
),
]
)
答案 2 :(得分:13)
只是为了附加正确答案,这是如何获取UnitTests / Supporting Files中文件的filePath的示例:
NSString *filePath = [[[NSBundle bundleForClass:[self class]] resourcePath] stringByAppendingPathComponent:@"YourFileName.json"];
XCTAssertNotNil(filePath);
这可能对某人有用。
答案 3 :(得分:3)
要访问本地文件:
NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
您可以使用以下方式进行异步访问并等待响应:https://github.com/travisjeffery/TRVSMonitor
如果您在测试目标(2)中添加了dataset1.json
:
NSString *p=[[NSBundle mainBundle] pathForResource:@"dataset1" ofType:@"json"];
NSLog(@"%@",p);
2013-10-29 15:49:30.547 PlayerSample [13771:70b] WT(0):/ Users / bpds / Library / Application Support / iPhone Simulator / 7.0 / Applications / 7F78780B-684A-40E0-AA35-A3B5D8AA9DBD /PlayerSample.app.app/dataset1.json
答案 4 :(得分:1)
我遇到的问题是应用程序代码试图访问bundle的标识符,例如bundleIdentifier,因为主要包不是我的单元测试项目,它将返回nil。
围绕这个在Swift 3.0.1和Objective-C中工作的黑客是在NSBundle上创建一个Objective-C类别并将其包含在您的单元测试项目中。你不需要桥接头或任何东西。此类别将被加载,现在当您的应用程序代码要求主包时,您的类别将返回单元测试包。
@interface NSBundle (MainBundle)
+(NSBundle *)mainBundle;
@end
@implementation NSBundle (Main)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
+(NSBundle *)mainBundle
{
return [NSBundle bundleForClass:[SomeUnitTest class]];
}
#pragma clang diagnostic pop
@end
答案 5 :(得分:0)
这是Swift版本,Xcode 7,iOS 9等。
let testBundle = NSBundle(forClass: self.dynamicType)
let path = testBundle.pathForResource("someImage", ofType: "jpg")
XCTAssertNotNil(path)
注意:someImage.jpg必须包含在您的测试目标中。
答案 6 :(得分:0)
Swift
版本基于公认的答案:
let url = URL(fileURLWithPath: Bundle(for: type(of: self)).path(forResource: "my", ofType: "json") ?? "TODO: Proper checking for file")
答案 7 :(得分:0)
快捷键5
let testBundle = Bundle(for: self)
使用上面某些答案中的let testBundle = Bundle(for: type(of: self))
不会编译,而是始终为我产生分段错误:11 的错误。