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.)
source to share
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 ):
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.
source to share