6

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.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
DogCoffee
  • 19,820
  • 10
  • 87
  • 120

3 Answers3

12

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)
}
DogCoffee
  • 19,820
  • 10
  • 87
  • 120
  • To complete this I'd add file removal at the end of the test. While it is in the temp directory, it doesn't have to be purged and unit tests shouldn't leave any state changed. – Nat May 07 '18 at 08:43
  • Fixed some of the deprecation warnings: let locToSave = path.appendingPathComponent("tests_partners") NSKeyedArchiver.archiveRootObject(newPartner, toFile: locToSave) let data = NSKeyedUnarchiver.unarchiveObject(withFile: locToSave) as? – Anna Billstrom Aug 17 '19 at 22:57
3

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.

Paulo Mattos
  • 18,845
  • 10
  • 77
  • 85
2

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
Anna Billstrom
  • 2,482
  • 25
  • 33