Sample project that shows the issue: https://github.com/skladek/RealmObjectMocking
I'm running into an issue with adding a protocol to an external dependency for testing. I'm receiving an Abort Trap 6 error when building my test target. Everything I've searched around this says that turning off optimization will solve it, but that hasn't worked for me. Here's my setup and what I'm trying to accomplish:
The external dependency is Realm, but I don't think the issue is related to it specifically. I'm trying to make a protocol that mimics the public interface of the main Realm object. This will let me write tests to ensure that my objects are calling the correct methods on the Realm object. Here's what I've added:
RealmProtocol.swift: The protocol that mimics the Realm interface.
import RealmSwift
protocol RealmProtocol {
func add(_ object: Object, update: Bool)
func beginWrite()
func commitWrite(withoutNotifying tokens: [NotificationToken]) throws
func object<Element: Object, KeyType>(ofType type: Element.Type, forPrimaryKey key: KeyType) -> Element?
func objects<Element: Object>(_ type: Element.Type) -> Results<Element>
}
Realm.swift: An extension to add RealmProtocol adherence to the Realm object. The Realm object is marked as final, adding the protocol as an extension seems to be my only option here. I can't subclass the Realm object to add it that way. If I can get the Realm object to adhere to the RealmProtocol, I can pass it around as RealmProtocol everywhere in my app and pass in a MockRealm object in my tests.
import RealmSwift
extension Realm: RealmProtocol {}
MockRealm.swift: My mock Realm object. This is only used in the test target. It will let me set flags to check that the correct method is called at the correct time.
import Foundation
import RealmSwift
@testable import RealmObjectMocking
class MockRealm: RealmProtocol {
var addCalled = false
var beginWriteCalled = false
var commitWriteCalled = false
var objectCalled = false
var objectsCalled = false
var objectReturn: Any?
func add(_ object: Object, update: Bool) {
addCalled = true
}
func beginWrite() {
beginWriteCalled = true
}
func commitWrite(withoutNotifying tokens: [NotificationToken]) throws {
commitWriteCalled = true
}
func object<Element: Object, KeyType>(ofType type: Element.Type, forPrimaryKey key: KeyType) -> Element? {
objectCalled = true
let object = objectReturn as? Element
return object
}
func objects<Element: Object>(_ type: Element.Type) -> Results<Element> {
objectsCalled = true
let realm = try! Realm()
return realm.objects(type)
}
}
What's happening: Everything works fine until I add the Realm.swift extension. At that point, I get the abort trap 6 when attempting to build my tests. If I remove that, my tests build, but I can't pass the Realm object around as RealmProtocol and I can't swap it out for MockRealm in my tests.
I'm not sure if this is a circular dependency issue or something else. I have to import RealmSwift in all 3 of those files. Possibly the compiler not liking something there?
It also seems strange that I can add an extension to a final class. Is that intended? Seems like an easy way to sidestep final.
Does anyone have a thought on what could be causing this or how I can get past the warning? Currently my solution is to make a RealmWrapper object that simply passes calls into an actual Realm object, but that's a shim where I don't think there needs to be one.
I have also filed a Radar for this since it crashes the editor in Xcode when opening MockRealm.swift if the Realm extension is in the project.