iOSで偽データを使用してテストする方法

高品質のソフトウェアを提供し、リグレッションを回避するには、すべてのiOSアプリケーションで単体テストを実装する必要があります。
オブジェクトのモックは、実際のAPIと同じAPIを使用して偽のオブジェクトを作成する単体テストの手法です。
この記事は、iOSアプリで最も頻繁に発生するシナリオに対して、偽データの使用方法と単体テストの作成方法に関するベストプラクティスを提供するために書かれています。

単体テストを作成する場合、アプリケーションターゲットの実際のデータを変更することは常に避け、代わりにテスト目的だけで偽のデータを使用する必要があります。

以下のパートでは、一般的に使用されるiOS APIの偽データを使用してテストを作成する方法について説明します。

ユーザーのデフォルト

ソフトウェア開発では、常にオブジェクトの依存関係を減らすことをお勧めします。最良の場合の依存関係は、それらを使用するクラスに注入する必要があります。

しかし、実際のiOS開発シナリオを確認すると、ほとんどすべてのプロジェクトは、データを保存または取得するためにAPIを直接呼び出すことでUserDefaultsを使用します。

したがって、プロトコルでAPIを抽象化するのではなく、UserDefaultsrをテストするための実用的なソリューションを提供しようとします。

UserDefaultsに2つの新しい関数を作成できます

単体テストターゲットのアプリケーションデータを変更しないことは常に良い習慣であるため、テストターゲットのユーザーデータを保存する別の場所を作成する必要があります。

この場合、userNamesの新しいオブジェクトをsuiteNameで初期化します。testDefaultsは、標準のUserDefaultsから完全に独立しています。

UserDefaultsを使用する簡単なテストを作成してみましょう

このデータは基本的にテストにのみ使用されるため、そのデータがアプリケーションファイルに残ったままにならないようにする必要があります。したがって、テストの完了後にこのストレージを削除する機能を作成します。

もちろん、このデータを消去するのに最適な場所は、単体テストクラスのtearDown関数です。

シンゲルトンオブジェクト

シングルトンオブジェクトはiOSの多くのAPIで非常に使用されており、NSFileManager、NSApplication、UIApplicationなどの多くの場所で見つけることができます。

シングルトンをテストする方法を知ることは、iOS開発者にとって知っておくと便利です。

この例では、アップルのiAdフレームワークを使用します。広告属性の詳細を要求する際の実際のデータの代わりに、ローカルJSON応答を取得するファイルを作成します。

iOSの優れた機能は、Swiftの拡張機能により、事前定義されたAPIに新しい関数を追加できるだけでなく、独自のカスタムプロトコルに準拠させることができることです。

AdvertismentClientプロトコルを定義しましょう

その後、デフォルトのADClientと次のような偽の広告クライアントの両方でこのプロトコルに準拠します

次に、依存関係を次のいずれかに変更します

private var adClient:AdvertismentClient = ADClient.shared()

または

private var adClient:AdvertismentClient = MockAdClient()

次のように使用します

このようにして、単体テストまたはライブアプリケーションターゲットからAPIを呼び出すかどうかに応じて、実際のデータをいつ使用し、いつテストするかを簡単に決定できます。

コアデータ

コアデータは、iOSで引き続きデータをキャッシュするために使用されています。コアデータエンティティのテストには注意が必要です。以下に、コアデータサービスの整理とデータの偽造の両方の優れた実践方法を説明します。

一般に、ほとんどの場合、プロジェクト全体でコアデータコードを使用するのではなく、データベース上の特定のデータをフェッチおよび書き込むサービスクラスを作成することは常に良いことです。

これには主に2つの利点があります。

  • 使用されている基礎となるデータベースから切り離されます。将来、コアデータを他のデータベースに置き換えたい場合は、1つのクラスでのみ変更を行う必要があります。
  • これにより、どのCoreDataStackを使用するか、または他のフレームワークで必要になる可能性のある他のセットアップを簡単に決定できます。

CoreDataStackプロトコルを作成し、その後、このプロトコルに準拠する2つのCoreDataStack、1つのMainCoreDataStackと1つのMockCoreDataStackを作成します。

DatabaseServiceは、アプリケーションターゲットで使用するか、単体テストターゲットで使用するかに応じて、いずれかによって初期化できます。

メインのコアデータスタックには、次のようなデフォルトのセットアップがあります

ユニットテストを常に行う場合、テスト中に現在の「実際の」オブジェクトの状態を変更しないでください。

そのため、偽のコアデータエンティティを作成する場合は、個別の永続ストアを作成し、メモリ内ストアタイプの構成を使用して、変更がディスクに保存されず、現在永続データから完全に分離されるようにします。

これで、デフォルトでMainCoreDataStackで初期化されるデータベースサービスを作成できるようになります。

そして、テストクラスでは、偽のデータスタックで初期化できます。

次のように、いくつかの簡単なテストを作成できます。

このアプローチを使用することにより、アプリケーションターゲットによって保存されているデータに影響を与えることなく、DatabaseServiceを簡単にテストできます。

ネットワークリクエスト

ネットワーク層をテストする場合、プロトコル指向のアプローチを使用してプロトコルを作成し、実際のNetworkServiceとMockNetworkServiceの両方でプロトコルに準拠し、その後、実際のサービスまたは模擬サービスを使用して依存関係を注入できます。

この記事では、モックとスタブをさらにうまく処理するOHHTTPStubsと呼ばれる本当に素晴らしいオープンソースライブラリを使用します。

このライブラリの良いところは、有名なiOSネットワークライブラリであるAlamofireとうまく機能することです。

ネットワークリクエストのスタブ作成は、OHHTTPStubsを使用すると非常に簡単になります。辞書を使用してカスタムレスポンスを提供することにより、特定のパスまたはホストのレスポンスを置き換えることができます。

その後、アプリから次のURLに送信されるすべてのリクエストは、代わりにカスタムレスポンスを返します。

LetsURL = URL(string:“ https://jsonplaceholder.typicode.com/todos”)!

また、カスタムレスポンスの優れた点は、レスポンスでエラーを返すだけで、エラーおよびエッジケースが正しく処理されるかどうかを簡単にテストできることです。

応答用のディクショナリを手動で構築するのは素晴らしい機能ですが、多くのプロパティを持つ大きなJSONデータを返したい場合、テストクラスでは面倒でメンテナンスが困難になります。

このような場合、JSONファイルを使用して、次のように応答をスタブできます。

これで、アプリがリクエストを送信するたびに、ファイルに保存したファイルmyResponse.jsonからレスポンスを取得します。

ただし、これらのファイルをアプリケーションと一緒に出荷すると簡単に表示できるため、これらのJSONファイルに機密情報を保存しないようにしてください。

詳細については、セキュリティトピックに関する私の記事を参照してください。

結論として

可能な限り回帰を避け、完璧なアプリケーションを提供しようとする場合、アプリケーションのユニットテストは必須です。

この記事では、iOS開発中に発生する一般的なケースのテストを提供する方法について説明しました。

UserDefaults、Singeltons、Core Data、およびNetwork Requestsをテストする方法について説明しました。

この記事が気に入った場合は、拍手してサポートを示してください。

iOS開発者のスキルを次のレベルに引き上げる多くの記事をご覧ください。

質問やコメントがありましたら、ここにメモを残すか、arlindaliu.dev @ gmail.comにメールしてください。