SwiftUIとCoreDataを使用するアプリのUnitTest環境構築

SwiftUIとCoreDataを組み合わせたアプリのUnitTest環境を構築する時のメモ

構築したいUnitTest環境

  • SwiftUIを使っている
  • CoreDataを使っている
  • XCodeが作ってくれたテンプレをスタート地点とする
  • プロジェクト作成時に、UnitTest, UITestをいずれもチェックした

上記の環境で、どうやってCoreDataを使うアプリのテスト環境を構築するかのメモ

CoreDataStackクラス

デフォルトで作成されるコードは、AppDelegate に NSPersistentContainer のインスタンスを保持させて、そこから取得した NSManagedObjectContext のインスタンスを SceneDelegate の中で.environment へ設定しています。

この形だと、UnitTestする時にも、AppDelegateが必要になり、すこし厄介です。CoreData関連の情報を保持するクラスを外部に独立させて作成し、そのクラスへのリファレンスを、アプリで保持するようにすると、テストしやすくなります。

CoreDataStackクラスの定義

AppDelegate 内に定義されていた CoreData 関連のコードをまとめた CoreDataStack クラスは、このようなものになります。

CoreDataStackの保持

上記で作ったCoreDataStackのインスタンスを何処かに保持させてアプリケーションの動作中に使うことになります。アプリケーションがどのように使うかによって、どこで持つべきかが変わります。ここでは、AppDelegateに保持させることとしました。合わせて、SceneDelegate での NSManagedObjectContext の取得方法も調整する必要があります。
AppDelegateのクラスに変数として以下を追加。

SceneDelegateは、以下のように修正

AppDelegate 内の変数 coreDataStack 経由でNSManagedObjectContextを取得するように変更。

UnitTest

アプリケーションでは、CoreDataへの参照は、AppDelegateで保持し、SceneDelegate実行時に使われます。
UnitTestでは、AppDelegateは必要ないので、UnitTestから直接CoreDataStackをインスタンス化してテストできます。
Setupの中で行っても良いですし、別関数にしても良いですが、以下のようなコードでNSManagedObjectContextを取得できます。

テストの改善

上記のコードから取得されるNSManagedObjectContextを使ってテストすることもできますが、CoreDataはデータをアプリ外に保持するために、過去に実行したデータが残っているかもしれないことを意識してテストする必要があります。つまり、アプリを動作させる時も、UnitTestも同じ環境になってしまうということです・・・・
ということで、テスト用のCoreDataStackを作ることを考えます。
自分で作るのも手ですが、ここにあるものを使わせてもらうのも手です。(他にも同様のライブラリはあります。)
ポイントは、SQLiteやXMLファイルをベースにするのではなく、全てをオンメモリで動作するように設定したCoreDataをテスト用に用意することです。もちろん、扱うManagedObjectModelは同じでなければいけません。
上記のライブラリを使うとそのようなことが簡単にできます。
上記のライブラリを使うとすると、テストのセットアップは以下のようになります。

MEMO
上で紹介したライブラリは、CoreDataに対しては、すごいことをしてくれるわけではなく、Bundleの.momファイルからManagedObjectModelを読んで、・・・ということをしてくれるライブラリです。勉強がてら自分で書いてみるのもアリですし、他のお気に入りのライブラリを使ってもOKです。他のライブラリを使う時には、StoreTypeを自分で指定できるAPIが用意されているかを確認してください。
これで、シミュレータ等の環境上のCoreDataのDBファイルを汚さずに、メモリ上のDBを対象としてテストすることができるようになります。

# 上記のライブラリを使うと、CoreDataStackをインスタンスかするだけではディスク上のデータを読まないので、以下のように明示的にloadする必要があります。

あとは、UnitTestにテストコードを追加するだけ

あとは、必要なEntityを作成して、テストするだけです。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です