web-dev-qa-db-ja.com

APIクライアントとラッパーの単体テスト

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

Wrapper --> Client --> External API

最初に、ClientWrapperの両方に対して一連のテストを作成しました。実際には、操作対象の適切な関数に転送することをテストしているだけです(WrapperClientで機能し、ClientはHTTP接続で機能します)。しかし、インターフェイスではなく、これらのクラスの実装をテストしているような気がするので、私はこれに不快に感じ始めました。理論的には、クラスを変更して別の完全に有効な実装にすることもできますが、呼び出されるはずの関数が呼び出されないため、テストが失敗します。それは私にとって脆弱なテストのように聞こえます。

この後、クラスのインターフェースについて考えました。テストは、クラスが実際にどのように実行するかではなく、実際に実行することを確認する必要があります。どうすればこれを行うことができますか?最初に頭に浮かぶのは、外部APIリクエストをスタブすることです。しかし、私は外部サービスを単純​​化しすぎることについて緊張しています。私が見たスタブ化されたAPIの例の多くは、返信定型文を返すだけであり、偽のAPIに対してコードが正しく実行されることをテストするだけの非常に簡単な方法のように思えます。別の方法は、サービスをモックすることですが、これは実行不可能であり、実際のサービスが変更されるたびに最新の状態に保つ必要があります。これは、やり過ぎや時間の浪費のように感じられます。

最後に、これを プログラマーSEの別の回答 から読みます。

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

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

しかし、私はまだWrapperクラスで立ち往生しています。次のオプションが表示されます。

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

  2. モックClientを作成します。今、私はそれをモックしてどこまで行くかを決めなければなりません-サービスの完全なモックを作成することは多くの労力を必要とします(ライブラリ自体に行った以上の作業)。 API自体はシンプルですが、サービスはかなり複雑です(基本的には、そのデータを操作するデータストアです)。また、モックを実際のClientと同期させる必要があります。

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

だから私はこれらの解決策のどれにも特に満足していません。あなたならどうしますか?これに対処する正しい方法はありますか?

15

[〜#〜] tldr [〜#〜]:困難にもかかわらず、サービスをスタブしてクライアントの単体テストに使用する必要があります。


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

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

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

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

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

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

とにかく、サービスをスタブ化したりリファクタリングしたりすることが政治的または実際的に問題外でない限り、おそらく上記と同様のことを行うでしょう。それが不可能な場合は、本当に優れた統合カバレッジを確保し、可能な限りテストセットアップを考慮して可能な限り頻繁に実行します。

HTH

10
Dan1701