APIクライアントとラッパーのユニットテスト


14

私は、開発中のAPIクライアントライブラリを単体テストするための最良の方法を見つけようとして、一周して回りました。このライブラリには、Client基本的にAPIとの1:1マッピングを持つWrapperクラスと、の上部でよりユーザーフレンドリーなインターフェイスを提供する追加のクラスがありますClient

Wrapper --> Client --> External API

私は最初の両方に対してテストの束を書いたClientし、Wrapper効果的にちょうど彼らが前方(上で動作するものは何でもの適切な機能にそのことをテストし、Wrapper上の動作Client、およびClientHTTP接続で動作します)。しかし、インターフェイスではなくこれらのクラスの実装をテストしているように感じるので、これに不快感を覚え始めました。理論的には、クラスを別の完全に有効な実装に変更することはできましたが、呼び出されると予想されていた関数が呼び出されていないため、テストは失敗します。それは私にとって脆弱なテストのように聞こえます。

この後、クラスのインターフェースについて考えました。テストでは、クラスが実際に行う方法ではなく、クラスが実際に意図したジョブを実行することを確認する必要があります。どうすればこれを行うことができますか?最初に頭に浮かぶのは、外部APIリクエストをスタブ化することです。しかし、私は外部サービスを単純​​化しすぎることに神経質です。私が見たスタブAPIの例の多くは、定型応答を提供しているだけです。これは、コードが偽のAPIに対して正しく実行されることをテストするだけの非常に簡単な方法のようです。別の方法はサービスをモックすることです。これは実行不可能であり、実際のサービスが変更されるたびに最新の状態に維持する必要があります。

最後に、私はこれを に、プログラマーSEに関する別の回答ました

リモートAPIクライアントの仕事は、特定の呼び出しを発行することです-これ以上でもそれ以下でもありません。したがって、そのテストでは、これらの呼び出しを発行することを確認する必要があります-これ以上でもそれ以下でもありません。

そして今、私は多かれ少なかれ確信しています-テストするとき、テストClientする必要があるのは、APIへの正しいリクエストを行うことだけです(もちろん、APIが変更される可能性は常にありますが、私のテストは合格し続けます-しかしそれは統合テストが役立つ場合)。以来Clientちょうど1:APIと1のマッピング、私の懸念は実際には適用されません別の有効な実装から変更について前に-の各メソッドの唯一の有効な実装がありますClient

しかし、私はまだにこだわっています Wrapperクラスにます。次のオプションが表示されます。

  1. Clientクラスをスタブ化し、適切なメソッドが呼び出されることをテストします。このように、私は上記と同じClientことをしていますが、APIの代用として扱います。これは私が始めたところに私をすぐに戻します。繰り返しになりますが、これはインターフェースではなく実装のテストの不快感を与えてくれます。のWrapper非常によく、完全に別のクライアントを使用して実施することができます。

  2. モックを作成しますClient。ここで、モックを作成する方法を決定する必要があります。サービスの完全なモックを作成するには、多くの労力が必要になります(ライブラリ自体に行った以上の作業)。API自体はシンプルですが、サービスは非常に複雑です(基本的に、そのデータに対する操作を備えたデータストアです)。そして再び、私は私のモックを本物と同期させておく必要がありますClientます。

  3. 適切なHTTPリクエストが行われていることをテストするだけです。これはWrapper、実際のClientそれらのHTTP要求を行うためにオブジェクトをため、実際に個別にテストするわけではありません。これは少しひどい単体テストになります。

したがって、これらのソリューションのいずれにも特に満足していません。あなたならどうしますか?これについて正しい方法はありますか?


サードパーティのライブラリが大雑把な作業のほとんどを行うこれらのシナリオでは、ユニットテストを避ける傾向があります(主に本当に意味のあるものをテストする方法でこれを行う方法がわからないため)。一般的に、これらのケースでは、おそらく模擬サービスを使用して統合テストを行います。多分誰かがこれらのための本当に意味のある単体テストを作る方法を知っている-私は私たちの制御下でシステムの最も重要なコンポーネントを優先する傾向がある。ここで、重要な部分は私たちの制御外です。:-(

回答:


10

TLDR:困難にもかかわらず、サービスをスタブ化し、クライアントユニットテストに使用する必要があります。


APIが常に一定のステータスを返し、消費も生成もしないエンドポイントのみで構成されている場合を除き、「リモートAPIクライアントのジョブが特定の呼び出しを発行すること、それ以上、それ以下」という確信はありません。任意のデータ。これは最も便利なAPIではありません...

また、クライアントが正しいリクエストを送信するだけでなく、応答コンテンツ、エラー、リダイレクトなどを適切に処理することも確認する必要があります。これらすべてのケースについてテストします。

ご指摘のように、ラッパー->クライアント->サービス-> DB以降のスタック全体をカバーする統合テストが必要ですが、すべての一部として統合テストを実行できる環境がない限り、主な質問に答えます多くの頭痛の種(共有テストデータベースなど)なしでCIをビルドするには、APIのスタブの作成に時間をかける必要があります。

スタブを使用すると、サービスの実装を作成できますが、サービス自体の下にレイヤーを実装する必要はありません。

RESTリソースの下にリポジトリパターンを実装することで、DIベースのソリューションを使用してこれを実現することを検討できます。

  • RESTハンドラーのすべての機能コードをIWhateverRepositoryの呼び出しに置き換えます。
  • RESTリソースから抽出されたコードを使用してProductionWhateverRepositoryを作成し、単体テスト中に使用するための定型応答を返すTestWhateverRespositoryを作成します。
  • DIコンテナを使用して、構成に応じてProductionWhateverRepositoryまたはTestWhateverRepository DLL /クラスなどを挿入します。

とにかく、サービスのスタブ化および/またはリファクタリングが政治的または実際的に問題にならない限り、おそらく上記と同様のことを引き受けます。不可能な場合は、統合カバレッジが本当に良好であることを確認し、使用可能なテストセットアップが与えられている限りできるだけ頻繁に実行します。

HTH

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.