【问题标题】:Load files in xcode unit tests在 xcode 单元测试中加载文件
【发布时间】:2013-10-09 16:37:30
【问题描述】:

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

我尝试了以下不起作用的方法

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

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

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

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

我做错了什么?

【问题讨论】:

  • 嘿,您将文件保存在哪里,可以通过“TestResource/TestData.xml”路径访问它?

标签: xcode unit-testing nsbundle


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 所以我发现使用它的标识符加载包是有效的。尽管此标识符不是 [NSBundle allBundles] 中数组的一部分。理想情况下它应该列出它...
【解决方案2】:

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

目标 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) 

【讨论】:

  • 及时更新
  • [self class] 是解决方法。 [NSBundle MainBundle] 在这里不起作用。这解决了我的问题。谢谢大佬。
【解决方案3】:

answer中所述:

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

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

目标 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)
}

【讨论】:

  • 在 Swift 示例中,我认为您的意思是在第二行使用“bundle”而不是“testBundle”。
  • 这个答案和前一年提供的基本一致。
  • @stevo.mit 抱歉!
【解决方案4】:

在 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")

【讨论】:

  • 这显示了 Swift 比 the most popular answer 更好的实践:没有强制解包,优先使用 URL 而不是路径,并且使用 Data 而不是 NSData
【解决方案5】:

我知道这个特定的问题是要求 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") }

【讨论】:

    【解决方案6】:
    1. 获取主包
    2. 使用主包获取本地模拟数据
    3. 从 JSON 加载数据

    让 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")
            }
        }
    

    【讨论】:

      【解决方案7】:

      需要注意的一点是(我花了好几分钟才弄清楚):

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

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

      【讨论】:

        【解决方案8】:

        Swift 4+

        我在这里没有找到最新的或使用 URL 的答案。

        首先将以下函数添加到您的 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
        }
        

        然后你可以在你的测试类中这样调用它:

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

        注意:出于安全原因,Apple 建议始终将 URL 用于资源(而不是路径)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-09-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-07-17
          • 2019-03-13
          • 2020-01-02
          相关资源
          最近更新 更多