NSURL到XCTest的测试包中的文件路径

时间:2013-10-11 02:03:23

标签: ios tdd nsbundle xctest

我正在尝试使用TDD和新的XCTest框架编写iOS应用程序。我的一个方法从Internet检索文件(给定NSURL对象)并将其存储在用户的文档中。该方法的签名类似于:

- (void) fetchAndStoreImage:(NSURL *)imageUrl

我正在尝试为这种方法编写测试,如果没有连接到互联网就不会失败。我的方法(取自之前的question)是使用NSURL将方法调用到本地文件系统中的图像。

当创建启用了单元测试的新项目时,Tests目录有一个名为“Supporting Files”的子目录。我想这是我的测试图像应该去的地方。我的问题是如何获得指向此目录中的图像的NSURL对象,因为我不希望测试图像与应用程序捆绑在一起。任何帮助表示赞赏。

8 个答案:

答案 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 buildswift 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)

  1. 您可以像任何目标一样引用捆绑文件。
  2. 检查文件是否在Copy Bundle Resources构建阶段(测试目标)中复制
  3. 要访问本地文件:

    NSURL*imageUrl=[[NSBundle mainBundle]URLForResource:@"imageName" withExtension:@"png"];
    
  4. 您可以使用以下方式进行异步访问并等待响应: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 的错误。