'Swift 2.0 Unit Testing for NSCoding

I am going to try and use the new testing features in Xcode 7 (code coverage) and Swift 2.0.

Using code coverage, I see that I am not testing my NSCoding methods.

enter image description here

For a trivial example of saving a few details, such as:

required init(coder aDecoder: NSCoder) {
    name = aDecoder.decodeObjectForKey("name") as! String
    time = aDecoder.decodeIntegerForKey("time")
}

func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeInteger(time, forKey: "time")
    aCoder.encodeObject(name, forKey: "name")
}

How do I go about testing these methods in an XCTest class.



Solution 1:[1]

Walking away from a problem always helps.

func testDecoder() {

    let path = NSTemporaryDirectory() as NSString
    let locToSave = path.stringByAppendingPathComponent("teststasks")

    let newTask = Task(name: "savename", time: "10")

    // save tasks
    NSKeyedArchiver.archiveRootObject([newTask], toFile: locToSave)

    // load tasks
    let data = NSKeyedUnarchiver.unarchiveObjectWithFile(locToSave) as? [Task]

    XCTAssertNotNil(data)
    XCTAssertEqual(data!.count, 1)
    XCTAssertEqual(data!.first?.name, "savename")
    XCTAssertEqual(data!.first?.time, 10)
}

Solution 2:[2]

Improving @DogCoffee answer a bit, in case you don't want to create actual files during tests and just instead encode and decode to a simple Data memory based buffer:

func testDecoder() throws {
    let savedTask = Task(name: "savename", time: "10")

    let encodedData = try NSKeyedArchiver.archivedData(withRootObject: [savedTask], requiringSecureCoding: false)
    let loadedTasks = try XCTUnwrap(try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(encodedData) as? [Task])

    XCTAssertEqual(loadedTasks.count, 1)
    let loadedTaks = loadedTasks.first! 

    XCTAssertEqual(loadedTask.name, "savename")
    XCTAssertEqual(loadedTask.time, 10)
}

This also uses the newer XCTUnwrap(expression) API to assert that an expression is not nil, and then return the unwrapped value.

Solution 3:[3]

The above answer (@dogcoffee's) is correct, adding some deprecation warnings that I've fixed

let locToSave = path.appendingPathComponent("teststasks")

NSKeyedArchiver.archiveRootObject(newPartner, toFile: locToSave)

let data = NSKeyedUnarchiver.unarchiveObject(withFile: locToSave) as? YourClass

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 DogCoffee
Solution 2
Solution 3 Anna Billstrom