Re: Anyone using CloudKit?


On Sep 1, 2020, at 10:38 AM, Jens Alfke <jens@...> wrote:

#2: How the heck does one write tests for CloudKit? … The only real solution I can imagine is to mock the entire CK API, which is feasible since it seems to be implemented in Obj-C, but that would be a big effort and you'd have to reproduce all the behaviors of the real system, which aren't documented.

I've made some progress on mocking by defining a protocol containing the CKDatabase methods I call; an empty extension to mark CKDatabase as implementing that protocol; and a mock class that implements the protocol. Then in my code I just change references to `CKDatabase` to `IndirectCKDatabase`, and allow the instance to be injected.

public protocol IndirectCKDatabase : AnyObject {
    var databaseScope: CKDatabase.Scope { get }
    func add(_ operation: CKDatabaseOperation)
    func save(_ record: CKRecord, completionHandler: @escaping (CKRecord?, Error?) -> Void)
    func delete(withRecordID recordID: CKRecord.ID, completionHandler: @escaping (CKRecord.ID?, Error?) -> Void)

extension CKDatabase : IndirectCKDatabase}

class MockCKDatabase : IndirectCKDatabase {

But in implementing the mock class I'm running into roadblocks:
  • The implementation of `add` needs to add metadata (dates, changeTag) to the CKRecord. But there's no way to create this metadata. The properties have no setters, and the only way to instantiate a record with metadata is to pass in an archived copy of the metadata, which can only be produced from a CKRecord that already has it…
  • Various operations need to return CKServerChangeToken instances. There's no way to create these at all, the class has no constructor.

I've been searching for other people's solutions to mocking, and it seems various people have gone down this road, but I haven't found anyone whose gotten farther than I have :(


Join { to automatically receive all group messages.