はじめに
こんにちは、iOSアプリ開発Gの深山です。
現在、所属プロジェクトでリアーキテクチャに取り組んでいます。その中でCoreDataのユニットテストを実装する機会があったのですが、日本語のわかりやすい記事がなかなか見つからなかったため、英語で執筆されている「Unit Testing Core Data in iOS」という記事を元にまとめてみました。
ユニットテストって?
表題に入る前に、まず「ユニットテストとはなんぞや」となっている人向けに、ユニットテストについて紹介します。
ユニットテスト(単体テスト)とは、プロジェクトを構成する比較的小さな単位(ユニット)の機能を正しく果たしているかどうかを検証するテストのことです。 「ボタンをタップするとアプリが新しい記録を作成する」という、シナリオでテストするのではなく、ボタンのタッチアップイベント、エンティティの作成、保存が成功したかどうかなど、より小さなアクションのテストを行います。
アプリのユニットテストの必要性は、以下のことが理由となります。
- アプリのUIに依存することなく、アプリのビジネスロジックのみを切り離してテストすることができる。
- リグレッションの心配なく、機能を追加したり、プロジェクトのリファクタリングを行うことができます。 テストが失敗した場合、問題箇所をすぐ見つけることができます。
- テストの時間を節約できます。3つの異なる画面をタップして入力欄にテストデータを入力したり、UIを手動で操作したりせず、アプリの任意の部分に対して小さなテストを実行できます。
ユニットテストの実装方法の詳細については、本記事のスコープ外となるため、説明を省略します。 こちらについては、AppleのドキュメントやiOS Unit Testing and UI Test Tutorialなどをご覧ください。
アクセスコントロールについて
デフォルトで、Swiftのクラスはアクセスレベルが
internalとなっています。つまり、独自のモジュール内からのみアクセスすることができます。
しかし、アプリとテストは別々のターゲットと別々のモジュールにあるため、通常、テストのモジュールからテスト対象のクラスを参照することはできません。
この問題を解決する方法は3つあります。
- アプリ内のクラスとメソッドを
publicとし、テストから参照できるようにする。(もしくはopenにして、サブクラス化できるようにする。) - File Inspectorでテスト対象のクラスを追加することで、テストにコンパイルされ、テストから参照できるようにする。
- 単体テストでインポート時に
@testableと記述して、インポートされたクラス内のものを参照できるようにする。
ユニットテストのための、CoreDataStackの作成
テストを行うために、まずはCoreDataStackをテスト用にセットアップします。
優れたユニットテストは、次のような「FIRST」に従います。
- Fast テストの実行に時間があまりにも時間がかかるなら、わざわざテストを実行する必要はありません。
Isolated テストを単独で実行、または、他のテストの前後で実行した場合に、正しく機能する必要があります。
Repeatable 同じテスト対象コードに対して、テストを実行するたびに、同じ結果が得られます。
Self-verifying テスト自体が成功または失敗を報告する必要があります。ファイルやコンソールのログの内容を確認する必要はありません。
Timely 開発とともにこまめにテストを実装することで、速やかにバグを発見し、ロジック単位で細かく品質を担保することができます。
ユニットテストを開始すると、アプリが起動し、実行中のアプリの環境内でユニットテストが実行されます。 しかし、以下のような場合で問題が発生する可能性があります。
深山侑花