廃墟

本ブログは更新を終了しました。 技術的な記事のみ、有用性を鑑みて残しておきます。

MagicalRecordによるモデルをGHUnitでテストする時に気をつけるべきこと

せっかくブログを始めたので、最近僕がハマった事例を紹介しようと思います。

MagicalRecordというライブラリを使っている事が前提です。
以下の解説記事がホッテントリに入っていたので、最近知ったという方もいるのでは。

ですが、以下の記事が参考になると思います。 普通はMagicalRecordを使うなら、mogeneratorを使うと思います。

GHUnitは有名なので、適当にぐぐってください。ユニットテスト用のツールです。

setUpClassとtearDownはこんな感じに書くと良いです。

- (void)setUpClass
{
    [MagicalRecord setupCoreDataStackWithInMemoryStore];
}

- (void)tearDown
{
    [YourObject truncateAll];
    [[NSManagedObjectContext contextForCurrentThread] saveToPersistentStoreAndWait];
}

このコードで特に重要なのが

[NSManagedObjectContext contextForCurrentThread]

の部分です。ここでもしも

[NSManagedObjectContext defaultContext]

を使ってしまうと、一つずつテストケースを実行する時には何も問題が起きないのに、一括で実行したときにはエラーが出るという、面倒な事態に陥ります。
その他の部分でも、同様の方法でcontextを取ってきてsaveするのが良いです。

ちなみにですが、setupCoreDataStackWithInMemoryStoreにしておくのも便利で、こうしておくと起動する度にCoreDataの内容がまっさらになるし、無駄なファイルが生成されるのが防げるしで、オススメです。

ようするに、GHUnitのテストはスレッドセーフになるように書けってことと、MagicalRecordがNSManagedObjectContextをカテゴリで拡張して用意しているメソッドはスレッドを意識しないと変なことになるぞって事です。 殆どのシーンではdefaultContextを使うメリットはなくて、contextForCurrentThreadを使った方が良いと思われます。内部のコードでも、省略可能なinContext引数をもつメソッドでは、省略時にcontextForCurrentThreadを用いています。