7

Where I can create an entity like so inside an XCTestCase test just fine:

let entity = NSEntityDescription.insertNewObject(
                   forEntityName: String(describing: Example.self), 
                   into: inMemoryManagedObjectContext)

But if I do it like this:

let item = Example(context: inMemoryManagedObjectContext)

A test would fail with...

failed: caught "NSInvalidArgumentException", "An NSManagedObject of
class 'myappTests.Example' must have a valid NSEntityDescription."

How am I supposed to test Core Data objects if I can't create them the way it is usually done?

sanmai
  • 29,083
  • 12
  • 64
  • 76
  • Are you adding your class files to test target? or Are you importing your MyAppTarget with @testable import MyAppTarget in your test class? – kmarin Aug 20 '17 at 07:24
  • I'm pretty sure I import everything I need because I can create objects and use them just fine the old way with `NSEntityDescription.insertNewObject` or related functions. – sanmai Aug 21 '17 at 01:25
  • there is a difference though, Can you just check if you Example class file is added to the app target or test target? – kmarin Aug 21 '17 at 06:46
  • Yes it is. If not then my example won't compile – sanmai Aug 21 '17 at 06:47
  • that is the issue, you should never add you class files to the test target, but rather import your app target as a module in your test class. – kmarin Aug 21 '17 at 06:48
  • have a look at this blog https://www.natashatherobot.com/swift-2-xcode-7-unit-testing-access/ , since ios7 it is not recommended to add your class files to test target, make sure you remove all of them from test target. – kmarin Aug 21 '17 at 06:51
  • We have plenty of CoreData tests in my project. I've just quickly check and both inserting methods works. There is nothing wrong with this code. – Jakub Aug 21 '17 at 20:19

1 Answers1

3

I had this problem too :) The problem, I guess, is that the entities are not known yet by CoreData. So, My Solution to be able to test it was to have an instance of NSPersistantContainer while testing.

var persistentContainer: NSPersistentContainer!
    override func setUp() {
        super.setUp()
        guard let model = CoreDataUtilities.model(withName: "ModelName") else {
            return XCTFail("Model should load")
        }
        storeFolder = FileManager.default.temporaryDirectory.appendingPathComponent("storeDirectory", isDirectory: true)
        let storeURL = storeFolder.appendingPathComponent("store.db")
        let storeInfo = NSPersistentStoreDescription(url: storeURL)
        storeInfo.type = NSSQLiteStoreType
        persistentContainer = NSPersistentContainer(name: "ModelName", managedObjectModel: model)
        persistentContainer.persistentStoreDescriptions = [storeInfo]
        return
    }

Now you can use CoreData the classic way.

sanmai
  • 29,083
  • 12
  • 64
  • 76
LastMove
  • 2,482
  • 1
  • 15
  • 25