I'm having some trouble figuring out how to make mocks/stubs for CloudKit and Core Data.
I have made some progress with my CloudKit service layer by injecting a database which conforms to a protocol I've written that essentially overrides CKDatabase
functions.
/// A protocol to allow mocking a CKDatabase.
protocol CKDatabaseProtocol {
func add(_ operation: CKDatabaseOperation)
func delete(withRecordID recordID: CKRecord.ID, completionHandler: @escaping (CKRecord.ID?, Error?) -> Void)
func fetch(withRecordID recordID: CKRecord.ID, completionHandler: @escaping (CKRecord?, Error?) -> Void)
func perform(_ query: CKQuery, inZoneWith zoneID: CKRecordZone.ID?, completionHandler: @escaping ([CKRecord]?, Error?) -> Void)
func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void)
}
extension CKDatabase: CKDatabaseProtocol { }
With this, I can inject the real CKContainer.default().publicCloudDatabase
into my service or I can create a mock class that conforms to the same protocol and inject my MockCKDatabase
into my unit tests service instance. This works for all the functionality except the add(operation)
function. I'm not sure how to get a CKQueryOperation
added to my MockCKDatabase
to have its completion blocks triggered.
For the Core Data portion, I am using the new NSPersistentCloudKitContainer
to sync the user's private database (while using my CloudKit service to make queries to my public database). I found an excellent blog about creating a Core Data stack that allows you to inject the store type when setting up the stack so that you can use NSSQLiteStoreType
in production and NSInMemoryStoreType
in testing.
However, when I try to use the in-memory solution I get the following error:
"NSLocalizedFailureReason" : "CloudKit integration is only supported for SQLite stores."
Is there some better solution to test CloudKit/Core Data? I would really like to have my service layers thoroughly tested.