Load files in xcode unit tests

XcodeUnit TestingNsbundle

Xcode Problem Overview


I have an Xcode 5 unit test project and some test xml files related to it. I've tried a bunch of approaches but I can't seem to load the xml files.

I've tried the following which does not work

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

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

Also if I try to preview all the bundles using [NSBundle allBundles] the unit test bundle does not appear in the list?

I tried to create a separate resource bundle and I can't seem to locate it programmatically although it does get built and deployed.

What am I doing wrong ?

Xcode Solutions


Solution 1 - Xcode

When running tests the application bundle is still the main bundle. You need to use unit tests bundle.

Objective C:

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

Swift 2:

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

Swift 3 and up:

let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "TestData", ofType: "xml")!
let xmlData = NSData(contentsOfFile: path) 

Solution 2 - Xcode

With swift Swift 3 the syntax self.dynamicType has been deprecated, use this instead

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
}

or

guard let ressourceURL = testBundle.url(forResource: "TestData", withExtension: "xml")

Solution 3 - Xcode

As stated in this answer:

When the unit test harness runs your code, your unit test bundle is NOT the main bundle. Even though you are running tests, not your application, your application bundle is still the main bundle.

If you use following code, then your code will search the bundle that your unit test class is in, and everything will be fine.

Objective C:

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

Swift:

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

Solution 4 - Xcode

Relative paths are relative to the current working directory. By default, that's / — the root directory. It's looking for that folder at the root level of your startup disk.

The correct way to get a resource that's within your bundle is to ask your bundle for it.

In an application, you'd get the bundle using [NSBundle mainBundle]. I don't know if that works in a test case; try it, and if it doesn't (if it returns nil or an unuseful bundle object), substitute [NSBundle bundleForClass:[self class]].

Either way, once you have the bundle, you can ask it for the path or URL for a resource. You generally should go for URLs unless you have a very specific reason to need a path (like passing it to a command-line tool using NSTask). Send the bundle a URLForResource:withExtension: message to get the resource's URL.

Then, for the purpose of reading a string from it, use [NSString stringWithContentsOfURL:encoding:error:], passing the URL you got from the bundle.

Solution 5 - Xcode

  1. Get main bundle

  2. Use main bundle to get local mock data

  3. Load data from 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")
         }
     }
    

Solution 6 - Xcode

One thing to note is(It waste me serval minutes to figure it out):

> Don't forget to add the test file to "Copy Bundle Resources" section of Build Phases

Without it, you couldn't load the file successfully.

Solution 7 - Xcode

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.

Solution 8 - Xcode

I know this specific question is asking for xml files, but if you're trying to do the same with json files, try this:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionArdenDevView Question on Stackoverflow
Solution 1 - XcodesashView Answer on Stackoverflow
Solution 2 - XcodeMarkHimView Answer on Stackoverflow
Solution 3 - Xcodestevo.mitView Answer on Stackoverflow
Solution 4 - XcodePeter HoseyView Answer on Stackoverflow
Solution 5 - Xcodezdravko zdravkinView Answer on Stackoverflow
Solution 6 - XcodeMartinZView Answer on Stackoverflow
Solution 7 - XcodeSverrissonView Answer on Stackoverflow
Solution 8 - XcodeJoseph FrancisView Answer on Stackoverflow