1

I have a set of NSManagedObject subclasses which are used by the ClassToBeTested.

The ClassToBeTested operates just on a few properties of the NSManagedObject subclasses and doesn't need relationships or the whole CoreData stack.

Can I somehow use the same objects in tests by just creating them in a regular way:

        let template = CoreDataClass()
        template.name = randomString(length: 40) // This fails!
        templates.append(template)

Currently it fails with error:

failed: caught "NSInvalidArgumentException", "-[CoreDataClass setTemplate_name:]: unrecognized selector sent to instance 0x600000af4c40"

Richard Topchii
  • 7,075
  • 8
  • 48
  • 115

1 Answers1

1

Although I get a different error (did not call designated initializer) when I try to do that, in either case, the answer to your question is: No, you cannot do that.

But with NSPersistentContainer nowadays, it is easy to use a singleton in-memory Core Data Stack for such testing. Include your data model in your test bundle, then put this in your test's global scope:

var sharedTestContext: NSManagedObjectContext = {
    // Swift is smart enough to execute this only once.
    let container = NSPersistentContainer(name: "<YourDataModelName>")
    let description = NSPersistentStoreDescription()
    description.type = NSInMemoryStoreType
    container.persistentStoreDescriptions = [description]
    container.loadPersistentStores { (description, error) in
        if let error = error {
            fatalError("Failed to load store for test: \(error)")
        }
    }
    return container.newBackgroundContext()
}()

And define a special managed object initializer for testing like this:

/**
 Initializes a managed object for testing

 - important:  This assumes your managed object subclass name is the same
 as its entity name.
 */
public extension NSManagedObject {
    convenience init(testContext: NSManagedObjectContext?) {
        let context = testContext ?? sharedTestContext
        /*  The following contraption is necessary to avoid warning:
         "Multiple NSEntityDescriptions claim the NSManagedObject subclass"
         For explanation see:
         https://stackoverflow.com/questions/51851485/multiple-nsentitydescriptions-claim-nsmanagedobject-subclass */
        let name = String(describing: type(of: self))
        let entity = NSEntityDescription.entity(forEntityName: name, in: context)!
        self.init(entity: entity, insertInto: context)
    }
}

Now you can create your test object thus:

let template = CoreDataClass(testContext: nil)
Jerry Krinock
  • 4,860
  • 33
  • 39