How to read in a local JSON file for testing
Asked Answered
E

2

22

I'm trying to write unit tests for json validation (since the app heavily relies on json from a rest API).

I have a local file that contains simple json: "goodFeaturedJson.txt"

The contents:

{
  "test": "TEST"
}

The test case:

- (void)testJsonIsValid
{
    Featured *featured = [Featured new];

    NSString* filepath = [[NSBundle mainBundle]pathForResource:@"goodFeaturedJson" ofType:@"text"];

    NSData *data = [NSData dataWithContentsOfFile:filepath];

    NSString *jsonString = [[NSString alloc] initWithContentsOfFile:filepath encoding:NSUTF8StringEncoding error:nil];//[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    NSLog(@"The json string is: %@", jsonString);

    id JSON = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

    STAssertTrue([featured jsonIsValid:JSON], @"Featured Data is NOT valid...");    
}

The test fails every time. The console prints:

The json string is: (null)

Why? I know why the test is failing, since clearly if the data is nil/null there will be no valid json, and the validator will break (which it should if its invalid).

There must be something simple I missed here, any ideas?

Ephor answered 15/5, 2013 at 17:6 Comment(5)
should ofType be ofType:@"txt"?Ganesha
The string is still null if I do that. I've tried text, and "json" as the type. The result seems to always be the same and I'm not sure why.Ephor
What does the error (that you apparently don't bother to check) say?Maui
Is *data null as well?Ganesha
The data parameter to JSONObjectWithData: is nil. (which is the error). Also yes, the NSData object is nil.Ephor
M
36

In a unit test you probably want to use [NSBundle bundleForClass:[self class]], and not [NSBundle mainBundle]. That's because the unit test is not a standalone app. With mainBundle you get something like /Applications/Xcode.app/Contents/Developer/Tools, but using bundleForClass gets you the bundle where your unit test class is located.

guard let pathString = Bundle(for: type(of: self)).path(forResource: "UnitTestData", ofType: "json") else {
    fatalError("UnitTestData.json not found")
}
Malorie answered 15/5, 2013 at 17:38 Comment(1)
Damn, didn't realize that about NSBundle; thanks! (This solved everything).Ephor
D
26

In Swift

Swift 5 and above

guard let pathString = Bundle(for: type(of: self)).path(forResource: "UnitTestData", ofType: "json") else {
    fatalError("UnitTestData.json not found")
}

guard let jsonString = try? String(contentsOfFile: pathString, encoding: .utf8) else {
    fatalError("Unable to convert UnitTestData.json to String")
}

print("The JSON string is: \(jsonString)")

guard let jsonData = jsonString.data(using: .utf8) else {
    fatalError("Unable to convert UnitTestData.json to Data")
}

guard let jsonDictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String:Any] else {
    fatalError("Unable to convert UnitTestData.json to JSON dictionary")
}

print("The JSON dictionary is: \(jsonDictionary)")

Swift 3 and 4

guard let pathString = Bundle(for: type(of: self)).path(forResource: "UnitTestData", ofType: "json") else {
    fatalError("UnitTestData.json not found")
}

guard let jsonString = try? NSString(contentsOfFile: pathString, encoding: String.Encoding.utf8.rawValue) else {
    fatalError("Unable to convert UnitTestData.json to String")
}

print("The JSON string is: \(jsonString)")

guard let jsonData = jsonString.data(using: String.Encoding.utf8.rawValue) else {
    fatalError("Unable to convert UnitTestData.json to NSData")
}

guard let jsonDictionary = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String:AnyObject] else {
    fatalError("Unable to convert UnitTestData.json to JSON dictionary")
}

print("The JSON dictionary is: \(jsonDictionary)")

Swift 2.2

    guard let pathString = NSBundle(forClass: self.dynamicType).pathForResource("UnitTestData", ofType: "json") else {
        fatalError("UnitTestData.json not found")
    }

    guard let jsonString = try? NSString(contentsOfFile: pathString, encoding: NSUTF8StringEncoding) else {
        fatalError("Unable to convert UnitTestData.json to String")
    }

    print("The JSON string is: \(jsonString)")

    guard let jsonData = jsonString.dataUsingEncoding(NSUTF8StringEncoding) else {
        fatalError("Unable to convert UnitTestData.json to NSData")
    }

    guard let jsonDictionary = try? NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as? [String:AnyObject] else {
        fatalError("Unable to convert UnitTestData.json to JSON dictionary")
    }

    print("The JSON dictionary is: \(jsonDictionary)")

*This incorporates Tom Harrington's answer which is in Objective C

Deliadelian answered 10/11, 2016 at 23:24 Comment(1)
Thanks for pointing out this bit: ` Bundle(for: type(of: self))` couldn't find that anywhere else and that made it work in Unit Tests!Meagher

© 2022 - 2024 — McMap. All rights reserved.