【Swift】 CoreDataのテスト方法を考えてみる

iOS, Swift

この記事は最終更新日から1年以上が経過しています。

はじめに

こんにちは。iOSアプリ開発グループの神山です。

最近CoreDataを触る機会が増えているのですが、テストについての記事がなかなか見つからず苦戦したため自分なりにまとめてみました。

今回はCoreDataのテストについて焦点を当てて進めていくため、CoreDataの概要などについては省略させていただくことをご了承ください。

下準備

テストを行うための下準備を行なっていきます。

はじめにデータモデルを定義していきます。
今回は namepriceのプロパティを持った Fruitというデータモデルを作成しました。
以下は自動生成されたコードになります。

次にアプリ内で定義したデータモデルを操作するためのクラスを作成します。

下図でもあるように、ここでは一つのインスタンスでCoreDataの操作をする NSPersistentContainerを作成するのが目的です。
このクラス内の viewContextのプロパティを使用してCoreDataに対してCRUDの処理を行っていきます。

Overview.png

Persistent container(NSPersistentContainer)のインスタンスが保持するもの

  1. Model(NSManagedObjectModel) → アプリで定義したモデルエンティティ(ここでは Fruit)
  2. Context(NSManagedObjectContext) → モデルエンティティのインスタンスの変更を追跡
  3. Store coordinator(NSPersistentStoreCoordinator) → モデルエンティティのインスタンスを保存・取得

次は先ほど作成した CoreDataManagerを使用して、実際にCoreDataに対してCURD処理を行う構造体を作成します。今回は CoreDataStorageという名前で作成しました。

CoreDataStorageを作成しましたら FruitがCoreDataStorageを使ってCURD操作ができるように関数を追加しておきます。

これで諸々のCoreDataの処理を行えるようになりました。

CoreDataのCURD処理

テストに入る前に一度どのようにデータを処理するのかを確認してみましょう。

【取得】

【作成】

【削除】

【更新】

CoreDataのテスト

テストを書くための準備が完了したのでテストコードを追加してみましょう。

はじめにCoreDataに対してCURD処理を行う構造体として作成した CoreDataStorageのテストを作成してみます。

次にCoreDataStorageを使ってCURD操作ができるように関数を追加したモデルエンティティ(Fruit)に対してのテストも作成してみます。

テストを実行してみますと、失敗する場合が出てくるかと思います。

例えば、既にデータをCoreDataに保存していたなどの場合です。テストを実行した際にそのデータも含めてテストが行われるためデータに不整合が生じてしまいます。

CoreDataのテストでは実行するタイミングや状況に応じてテストの結果が変わってしまうことがあるため、これを防ぐ必要があります。

テスト用のCoreData設定

CoreDataではデータの書き込み方法を変更することで、アプリとは別にテストのための領域を作成することができます。これを用いてテストではディスク上ではなくメモリに書き込むように変更してみましょう。CoreDataManagerのファイルに関数を追加します。

そして、上記で作成した関数を用いて、テストではメモリ上に書き込むを行う persistentContainerを作成し設定します。

これでアプリ上でCoreDataにデータを保存した状態でテストを実行したとしてもテストが成功することが確認できるかと思います。

おまけ

CoreDataをメモリ上に保存する方法として以下の方法もあります。

ただ、このように設定するより初めに紹介した /dev/nullへの書き込みの方が好ましいとの記事を見つけました。AppleのNSInMemoryStoreTypeのドキュメントが更新されていないため最新の推奨方法は不明瞭ですが、 /dev/nullを使われることをお勧めします。

また、テストにおける副作用を減らすという観点で、テストの際にはテスト用のAppDelegateを使用することも効果的です。具体的な作成方法はこちらの記事がとても参考になりました。

テスト用のAppDelegateを使用してテストコードを書き直すと以下のようになりました。

TestAppDelegate内でCoreDataの persistentContainerを設定する処理を入れることにより、各テストファイル内の setUp()で設定する必要がなくなり、共通化することができました。

さいごに

CoreDataのテストに関してご紹介しましたが、テストコードを書くことはアプリの品質を保つ上でもとても重要な要素であるため、より良いテストコードを書くために引き続き調査を続けていこうと思います。

最後まで記事を読んで頂き、ありがとうございました。

参考文献

https://www.donnywals.com/setting-up-a-core-data-store-for-unit-tests/

https://qiita.com/y-okudera/items/bf91374fdb4acfab927c

https://developer.apple.com/documentation/coredata/setting_up_a_core_data_stack

https://developer.apple.com/videos/play/wwdc2018/224/?time=1838

iOS, Swift