68

我有一个 Xcode 5 单元测试项目和一些与之相关的测试 xml 文件。我尝试了很多方法,但似乎无法加载 xml 文件。

我尝试了以下不起作用

NSData* nsData = [NSData dataWithContentsOfFile:@"TestResource/TestData.xml"];

NSString* fileString = [NSString stringWithContentsOfFile:@"TestData.xml" encoding:NSUTF8StringEncoding error:&error];

另外,如果我尝试使用 [NSBundle allBundles] 预览所有包,单元测试包不会出现在列表中吗?

我尝试创建一个单独的资源包,但我似乎无法以编程方式找到它,尽管它确实已构建和部署。

我究竟做错了什么 ?

4

8 回答 8

113

运行测试时,应用程序包仍然是主包。您需要使用单元测试包。

目标 C:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"TestData" ofType:@"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:path];

斯威夫特 2:

let bundle = NSBundle(forClass: self.dynamicType)
let path = bundle.pathForResource("TestData", ofType: "xml")!
let xmlData = NSData(contentsOfFile: path)

Swift 3 及更高版本:

let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "TestData", ofType: "xml")!
let xmlData = NSData(contentsOfFile: path) 
于 2014-04-23T10:36:51.400 回答
15

使用 swift Swift 3,语法self.dynamicType已被弃用,请改用它

let testBundle = Bundle(for: type(of: self))
guard let ressourceURL = testBundle.url(forResource: "TestData", ofType: "xml") else {
    // file does not exist
    return
}
do {
    let ressourceData = try Data(contentsOf: ressourceURL)
} catch let error {
    // some error occurred when reading the file
}

或者

guard let ressourceURL = testBundle.url(forResource: "TestData", withExtension: "xml")
于 2016-09-21T08:47:40.540 回答
7

如本答案所述:

当单元测试工具运行您的代码时,您的单元测试包不是主包。即使您正在运行测试,而不是您的应用程序,您的应用程序包仍然是主包。

如果您使用以下代码,那么您的代码将搜索您的单元测试类所在的包,一切都会好起来的。

目标 C:

NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSString *path = [bundle pathForResource:@"TestData" ofType:@"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:path];

迅速:

let bundle = NSBundle(forClass: self.dynamicType)
if let path = bundle.pathForResource("TestData", ofType: "xml")
{
    let xmlData = NSData(contentsOfFile: path)
}
于 2015-07-27T11:11:36.363 回答
2

相对路径是相对于当前工作目录的。默认情况下,这是 / — 根目录。它正在启动磁盘的根目录中查找该文件夹。

获取捆绑包中资源的正确方法是向捆绑包索取它。

在应用程序中,您将使用[NSBundle mainBundle]. 我不知道这是否适用于测试用例;试试看,如果没有(如果它返回nil或一个无用的捆绑对象),替换[NSBundle bundleForClass:[self class]].

无论哪种方式,一旦你有了包,你就可以向它询问资源的路径或 URL。您通常应该使用 URL,除非您有非常具体的原因需要路径(例如使用 NSTask 将其传递给命令行工具)。向捆绑包发送URLForResource:withExtension:消息以获取资源的 URL。

然后,为了从中读取字符串,使用[NSString stringWithContentsOfURL:encoding:error:],传递您从包中获得的 URL。

于 2013-10-08T01:00:24.247 回答
1
  1. 获取主包

  2. 使用主包获取本地模拟数据

  3. 从 JSON 加载数据

    let mainBundle = Bundle(identifier: "com.mainBundle.Identifier")
    if let path = mainBundle?.path(forResource: "mockData", ofType: "json") {
         do {
             let testData = try Data(contentsOf: URL(fileURLWithPath: path))
             networkTestSession.data = testData
         } catch {
             debugPrint("local json test data missing")
         }
     }
    
于 2020-04-20T11:34:10.123 回答
1

Swift 4+

I found none of the answers here up–to date or using a URL.

First add the following function to your testClass:

/// getFile. Opens a file in the current bundle and return as data
/// - Parameters:
///   - name: fileName
///   - withExtension: extension name, i.e. "json"
/// - Returns: Data of the contents of the file on nil if not found
static func getFile(_ name: String, withExtension: String) -> Data? {
    guard let url = Bundle(for: Self.self)
            .url(forResource: name, withExtension: withExtension) else { return nil }
    guard let data = try? Data(contentsOf: url) else { return nil }
    return data
}

Then you can call it in your test class like this:

func test() throws {
    let xmlData = Self.getFile("TestData", withExtension: "xml")
    XCTAssertNotNil(xmlData, "File not found")
}

Note: Apple recommends that URL's should always be used for resources (not paths) for security reasons.

于 2021-07-23T02:14:33.190 回答
1

需要注意的一件事是(它浪费了我几分钟来弄清楚):

不要忘记将测试文件添加到构建阶段的“复制捆绑资源”部分

没有它,您将无法成功加载文件。

于 2020-07-02T11:45:31.290 回答
0

我知道这个特定的问题是要求xml文件,但如果你想对 json 文件做同样的事情,试试这个:

let url = Bundle.main.url(forResource: "data", withExtension: ".json") guard let dataURL = url, let data = try? Data(contentsOf: dataURL) else { fatalError("Couldn't read data.json file") }

于 2019-10-26T18:11:05.297 回答