CoreDataのユニットテストを実行する

iPhoneアプリのデータ管理に永続化処理が必要だったのでCoreDataを使ってみた。iOSにはフレームワークとしてSQLiteが含まれているので自分でゴリゴリとSQLを書いても良いけれど、たまには気分を変えて他の手法を使ってみるのも悪く無いだろう。(ということにしておく)

CoreDataについてはサンプルコードや参考書籍も出回っているおり、情報が豊富で特に難しい点もない。新しい技術に特有の「最初の基本的な概念」さえクリア出来れば、あとはコードを書けるはずだ。永続化やクエリの処理を任せられるのは良いものの、CoreDataの欠点は記述が冗長なところ。単純に同程度の機能を実装する場合、SQLiteよりもCoreDataの方は面倒な記述が必要となるので、CoreDataはツカエナイという評価も有るようだ。

既存のデータベースを使う場合はFMDBのほうが楽です。CoreDataを使うべき理由は正直分かりませんでした。

FMDBとCoreData - ござ先輩のiPhone/iPad アプリ開発奮闘メモ - iPhoneアプリ開発グループ

MacCocoaの方ではGUIとCoreDataの連携がうまく出来る仕組みになっていて、実際iOSの方でもデフォルトのCoreDataアプリのコードを見れば分かるように、UITableViewControllerのデータ管理を上手く担えるだけの機能は用意されている。CoreDataが登場した時には「自分で書くコード量が削減出来る」ことが話題に上がったのだけど、iOSの場合、MacほどにはUIの種類が多くないので、本来持っている機能を十分に発揮出来ていないような印象も有る。この辺は、機能が豊富なMacフレームワークを持ってきたが故の制約なのかも知れないし、Macの技術的な経緯を知らずにいきなりiPhoneの開発に入った開発者ならやむを得ない判断かも知れない。

さらに、Mac OS X 10.4ではモデルレイヤの強化を行う。Core Dataの登場だ。Core Dataの目的を一言で言うと、データモデリングやクエリーといった、データベースの概念をデスクトップアプリケーションに取り込むことである。具体的には、データモデルの設計、オブジェクトの永続性、オブジェクトコンテキストの管理、などのサポートが加わる。

http://journal.mycom.co.jp/special/2005/cocoamvc/index.html

CoreData自体の機能は無事に実装できたものの、ユニットテストでは例外が発生してしまいテストが実行できなかった。

Test Case '-[StorageTest testBasic]' started.
2011-02-19 19:46:01.518 otest[31376:903] -[MyDataManager managedObjectModel](68) - modelPath:(null)
2011-02-19 19:46:01.520 otest[31376:903] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSURL initFileURLWithPath:]: nil string parameter'

例外の発生状況を確認したところ、モデルファイルが適切に読み込まれていないと分かった。対策方法は下記の2つ。

  1. モデルファイルをビルド対象に含める
    *.xcdatamodeldファイルを選択してCommand+Iで情報画面を開き、「ターゲット」としてユニットテストチェックボックスをオンにする。(通常のアプリケーションの方にはオフのままだけど)
  2. モデルパスを追加する
    モデルのパスがアプリケーションとユニットテスト実行時では異なるので、下記のようにアプリケーション用パス指定と、ユニットテスト用パス指定を両方記載しておく。(ユニットテスト用タイプ指定は"mom"であること。"momd”のままでは失敗してしまう)
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"MyModel" ofType:@"momd"];
if(!modelPath){
	modelPath = [[NSBundle bundleForClass:[self class]]
					  pathForResource:@"MyModel" ofType:@"mom"];
}

これで無事にCoreDataのユニットテストもパスするようになった。



関連