2016-08-15 12 views
2

私のパーシスタンス層にrealm-cocoaを使用しています。 realmrealm-cocoaを模擬する方法

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 
} 

に応じたクラスの一つは、その後、私のテストコードでは、私はRealmInterfaceの嘲笑バージョンを書くことができますし、Constructor Injectionを使用してRealmMetaDataインスタンスに注入があります。

模擬したRealmInterfaceを実装すると、空のリストを返すようにobjects関数をモックするのは非常に難しいことがわかりました。ファンクションシグネチャResults<T>の戻り値の型はRealm Frameworkによって提供される型であり、使用可能な空のコンストラクタは存在しないためです。ここで私は立ち往生している。

そのResult<T>finalキーワードのクラスですので、空のコレクションを取得するためのプライベートメソッドを使用するためにサブクラス化することもできません。

ありがとうございます!

+0

まず、テストクラス内でメモリ内のRealmを保持して管理し、すべてのメソッドをそのクラスに転送することをお勧めします。 – Dmitry

+0

@ドミトリーええ、助けてくれてありがとう。私はそれを受け入れることができます答えとしてこのコメントを書くだろうか? –

答えて

1

私がコメントで示唆したように、テストクラス内で内部メモリのRealmを使用し、Result<T>を返すすべてのメソッドを転送することができます。

0

結果ではなく自分のプロトコルを返すことになります。だから私はAnyRealmCollection<T>でこのプロトコルの実装を持っていて、もう1つは[T]であるので、メモリ内のRealmオブジェクトのないテストでは簡単に嘲笑します。

+0

私はこのアプローチを理解していますが、この方法でテストを容易にするためにコードを変更するのは良い習慣ではありません。 –

+0

@KevinR何のために? – ReDetection

+0

私の2セントは、しかし、コードを変更すると、複雑さが増し、そのために間違いが発生する可能性があります。さらに、テスト中に実装を変更すると、実際には実動コードで使用される表現が異なる結果につながる可能性がある場合、コードが正常に動作すると考えることができます。 –