Search code examples
swiftunit-testingrealm

How to mock realm-cocoa in swift


I'm using realm-cocoa for my persistence layer. There is one of the classes depending on realm

class RealmMetaData : AbstractMetaData {
    var realm: RealmInterface
    var isFirstLaunch: Bool = false
    init(realm: RealmInterface = try! Realm()) {
        self.realm = realm
        let results = realm.objects(MyClass.self)
        self.isFirstLaunch = (results.count == 0)
        if (self.isFirstLaunch) {
            realm.write {
                realm.add(MyClass())
            }
        }
    }
    // some code
}


protocol RealmInterface {
    // using a protocol based approach of mocking
    func objects<T: Object>(type: T.Type) -> Results<T>
    func write(@noescape block: (() throws -> Void)) throws
    func add(object: Object)
}

extension Realm: RealmInterface {
    func add(object: Object) { self.add(object, update: false) }
    // there is a method for Realm with signature: add(object:Object, update:Bool = false)
    // but swift extension dose not permit default function parameter, hence the wrapping
}

Then in my test code, I can write a mocked version of RealmInterface and inject it to the RealmMetaData instance using Constructor Injection.

When implementing the mocked RealmInterface, I found that's very difficult to mock the objects function to return an empty list. Because the return type of the function signature Results<T> is a type provided by the Realm Framework and there is no empty constructor available. Here is where I'm stuck.

That Result<T> is a class with final keyword so I also can't subclass it to use it's private methods to fetch an empty collection.

Thanks in advance!


Solution

  • As I suggested in a comments you can just use an internal in-memory Realm inside your test class and forward all methods that return Result<T> to it.