Inserting CoreDataNewObjectForEntityForName causes custom class to fail when unit tested

I have an AEUser class that is a subclass of NSManagedObject. This class has a method that creates a new instance of itself. For the default target, the normal route works well:

static func newDefaultUser(moc: NSManagedObjectContext) -> AEUser {
    let newUser = NSEntityDescription.insertNewObjectForEntityForName("AEUser", inManagedObjectContext: moc) as! AEUser
    newUser.uid = sDefaultUser // some string constant
    newUser.name = sDefaultUser // some string constant
    return newUser
  }

      

However, when you execute an XCTestCase that uses the same function to create a new user, a runtime error occurs at runtime. I may suddenly not add a new object to the AEUser. In the default target, everything worked fine.

Now it's interesting that the longer version of the above code works flawlessly for the test case. Now the throw is, of course, no longer needed. But the above code should create the same object. Also, when using breakpoints and looking at the actual object assigned to the new user above, it appears to be an AEUser object as it should be.

private static func newDefaultUser(moc: NSManagedObjectContext) -> AEUser {
    let entity = NSEntityDescription.entityForName("AEUser", inManagedObjectContext: moc)
    let newUser = AEUser(entity: entity!, insertIntoManagedObjectContext: moc)
    newUser.uid = sDefaultUser // some string constant
    newUser.name = sDefaultUser // some string constant
    return newUser
  }

      

Can someone explain why the above code does not work when using XCTestCase / a separate test target, specifically why the execution fails at runtime despite the above code apparently creates an object of the appropriate type, just like the second option?

(Running Xcode 6.3.2 and iOS 8.3 SDK.)

+3


source to share


1 answer


I had a similar problem. Took a bit of debugging to figure it out. Hope this works for you too.

I think the problem is that the cast is as! AEUser

trying to use MyAppTests.AEUser

, which doesn't seem to match what your data model wants the class to be (maybe it wants MyApp.AEUser

). You must use MyApp.AEUser

so that the data model can reference correctly. Try debugging your tests with some breakpoints and create a random instance AEUser

and see what Xcode is all about. I bet it's you MyAppTests.AEUser

.

My solution looked like this: I have an object called Team

that exists in an application called Somersault

. So, in my data model (you are making a class like this because this ):

enter image description here

Then make sure your subclass NSManagedObject

is public and all of its properties:

public class Team: NSManagedObject {
   @NSManaged public var name: String
}

      



Then in a test file in your test unit (mine was SomersaultTests

), point to the original unit:

import Somersault

      

And use your subclass as usual. Make sure you don't have any files NSManagedObject

in the compiled sources for your test unit; you want your test module to reference the original module .

Now you can directly route yours NSManagedObject

like this:

let newTeam: Team = NSEntityDescription.insertNewObjectForEntityForName("Team",
    inManagedObjectContext: self.moc!) as! Team

      

Good luck.

+1


source







All Articles