I am working on a iOS project that uses core data. I am using swift. The Core Data stack is setup right and all seems to be fine. I have created a class for an entity (NSManagedObject) called TestEntity. The class looks like this:
import UIKit
import CoreData
class TestEntity: NSManagedObject {
@NSManaged var name: NSString
@NSManaged var age: NSNumber
}
So, then I try to insert a new TestEntity in code using this line of code:
let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity
I then get this error:
I have seen some answers on stack overflow that say that I need to worry about the module name. So then I looked that up on the docs: https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/WritingSwiftClassesWithObjective-CBehavior.html
Then I went in the core data entity for TestEntity and in the class field I entered myAppName.TestEntity
When I run the app this line:
let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity
still gives me the same error.
What else could I be doing wrong?
EDIT: So, I was able to make the app not crash anymore by changing the TestEntity NSManagedObject class to: import UIKit import CoreData
@objc(TestEntity) class TestEntity: NSManagedObject {
@NSManaged var name: NSString
@NSManaged var age: NSNumber
}
So, I added the @objc(TestEntity) in it. This works with or without adding the appName before the TestEntity class name in the core data data model inspector.
This works, but, when I run tests this line still crashes:
let te: TestEntity = NSEntityDescription.insertNewObjectForEntityForName("TestEntity", inManagedObjectContext: ctx) as TestEntity
So I found that this is an issue for other people: How to access Core Data generated Obj-C classes in test targets?
How can we get core data to work in tests in swift. I am NOT using a bridging header in the app target and it all works great. The test target still crashes though.
How can I fix the test target so it can run core data tests?
The code example from Ludovic does not cover subentities. So when setting a parent entity in CoreData, the app crashes.
Adapted the code to take subentities into account:
I also faced similar issue when I tried to write unit test cases for a sample app (MedicationSchedulerSwift3.0) written in Swift 3.0, apart from implementing solution provided by johnford I created a category on XCTestCase to setup an NSManagedObjectContext with in-memory store by using below code:
And used it like this:
In case if someone needs more examples they can look at unit test cases over here - MedicationTests
With Xcode 7, and
@testable
, you should no longer need to update themanagedObjectClassName
or use other hacks. Here's what I did to get it working in Xcode 7.2.@testable
line to the top of all of your test classes:If you're still having issues you may want to try these additional tips: https://forums.developer.apple.com/message/28773#28949
I fought with this one for a while so I hope it helps someone else out.
It's because the CoreData framework is still in Objective-C. Swift uses namespaced-classes, so for CoreData to find your swift classes you have to specify the Class name with it's namespace like this:
The problem your will have is that your App does not have the same namespace as when you are running you tests.
<AppName>.<ClassName>
vs<AppName>Tests.<ClassName>
EDIT: Solution for running as App and Tests
I just wrote a piece of code to solve the
<AppName>.<ClassName>
vs<AppName>Tests.<ClassName>
issue. The solution I use at this time (Xcode 6.1) is to NOT fill theClass
field in the CoreData UI (shown above), and to do it in code instead.This code will detect if you are running as App vs Tests and use the right module name and update the
managedObjectClassName
.I think I'm getting similar results to you. I was unable to get my tests working with the line
But I could get the tests running with :
My Entity looks like :