web-dev-qa-db-ja.com

外部APIのクエリを唯一の目的とする関数をどのようにテストしますが、APIは複雑なクエリ構文を使用しますか?

実際のロジックは、外部APIのクエリ構文のみです。それがapiをクエリするかどうかをテストするのではなく、正しいデータが返されるようにクエリすることをテストしたいです。たとえば、いくつかの擬似コード:

function retrieve_related_data(id)
{
  query = "[potentially long, syntactically complex query that
            uses param id to get some data]";
  results = api_wrapper.query(query);
  return results;
}

構成されたAPIを使用したより具体的な例:

function retrieveLifeSupportingObjectsWithinRegion(id)
{
  query = "
    within region(" + id + ") as r
    find objects matching hydration>0 and temp_range has 75
    send name, id, relative(position, r)        
  ";
  results = astronomicalObjectApiWrapper.query(query);
  return results;
}

クエリは、APIに固有の構文であり、複雑であり、同じまたは類似の結果を得るには複数の方法があります。この関数の目的は、idで識別されるデータを取得することではなく、idで識別されるデータとのあいまいな関係に基づいて他のいくつかの要件を満たす他のデータのサブセットを見つけることです。その他の要件は、idに関係なく常に同じですが、システムが変更されると、時間とともに変化する可能性があります。たとえば、サンプルAPIが重力情報のサポートを追加した場合、結果を絞り込むために重力も使用するようにクエリを変更することができます。または、温度範囲を確認するためのより効率的な方法を考え出しても、結果は変わりません。

テストしたいのは、与えられた入力idに対して正しいデータセットが返されるということです。これをテストして、誰かがidに基づく正しいデータを返さないようにクエリを混乱させた場合に失敗するようにしますが、クエリを変更して絞り込めるようにしたいテストを変更する必要もありません。

私が検討したオプション:

  1. APIをスタブ化することもできますが、それは単純すぎる(クエリにidが存在することを確認し、存在する場合は予期されたデータセットを、存在しない場合は予期しないセットを返す)、もろい(クエリ文字列が関数の内容とまったく同じであることを確認します)、または複雑すぎます(使用されているクエリが構文的に正しいことを確認しますandは正しいデータが返されます)。

  2. クエリを実際のAPIに送信することはできますが、テストシステムの制御外で、外部システムのデータが変化すると、予想される結果が時間とともに変化する可能性があります。

  3. 実際のapiのデータを制御するために、実際のapiのテストインストールをセットアップすることを検討することもできますが、それは大変な労力です。

私は#2に寄りかかっており、これを頻繁に実行されない統合テストのようにし、外部システムのデータの変更がテストを中断させる頻度を確認しています。今のところそれが最も簡単だと思いますが、私が考えていない代替案や、この問題に取り組むためのより良い方法があるかどうか疑問に思っています。任意のアドバイスをいただければ幸いです。

16
Joshua Coady

関数をテストする外部API応答を検証しているように見えるかもしれませんが、それは完全に真実ではありません。どういうわけか、外部APIと、APIが実行されている環境をテストします。

私たちのテストは、サードパーティによって書かれたものではなく、私たちが書いたコードの予想される動作を保証するために取り組む必要があります。

ある程度までは、依存するAPIとライブラリの適切な機能を信頼する必要があります。たとえば、通常、実装するフレームワークコンポーネントはテストしません。

なぜそう言うのですか?

テストしたいのは、与えられた入力IDに対して正しいデータセットが返されることです。

ここで何がテストされますか?あなたが言ったように、データとその正確さは私たちの管理下にないので、私たちはテスト段階の成功を私たちが何も管理していない外部エージェントに制限するでしょう。これらのテストは 非決定的かつ決定的に、構築パイプラインでこの種のテストを望まない になる候補です。

別の問題は、契約の検証です。私は非常に便利だと思います 契約テスト1 リリースや展開の前に、統合が期待どおりに機能していることを確認します。

これをテストして、誰かがクエリをめちゃくちゃにして、IDに基づく正しいデータを返さなくなった場合に失敗するようにします

クエリは問題ないが、APIのバグが原因でデータが間違っている場合はどうなりますか?データが制御不能なだけではありません。論理もそうです。

機能テストまたはエンドツーエンドテストを実装すると、ここで役立つ場合があります。これらのテストに対処して特定の実行パスを検証することで、APIが誤ったデータを返した場合に、予期しない動作や出力が発生する可能性があります。一方、クエリの形式が不適切な場合、APIがエラーをスローすることを期待します。

しかし、私はまた、テストを変更する必要なく、人々がクエリを変更してそれを改良できるようにしたいと思っています。

そのような目的のためのツールを実装することをお勧めします。それは次のように簡単かもしれません:

  • テストとして実行されるが、テスト計画に属していないクラス
  • シェルスクリプト+カール

またはもっと洗練されたもの。たとえば、スタンドアロンクライアント。

いずれにせよ、問題の関数は、2種類のテストに値するものです。

  • 単体テスト。言ったように、外部APIをスタブする必要がありますが、単体テストの目的はそれだけです。依存関係を分離するコードをテストします。

  • 統合テスト。コードが正しいリクエストを送信するだけでなく、応答コンテンツ、エラー、リダイレクトなどを適切に処理することを確認してください。これらすべてのケースに対してテストを行いますが、データはテストしません

サイドノート:あなたの質問は-アプリのSQLステートメントをどのようにテストするのですか?に似ています

関連する質問


1:あなたはこれに関する@DocBrownの回答に興味があるかもしれません topic

7
Laiv

生成されたクエリ文字列が期待値と一致することを確認するユニットチェックを見ました。

しかしながら。これは、使用が制限されている場合には私の意見でした。クエリ構文は複雑でバグが多い可能性があり、Aにはチェックする可能性が無限にあり、Bが文字列が「正しく」生成された場合でも、ライブ環境で予期しない結果が返される可能性があります。

私はあなたがオプション2に行くのは正しいと思います。ライブインスタンスに対して統合テストを実行します。

それらが非破壊的である限り、これらは、エラーの原因を特定しませんが、キャッチするので、最初に記述する必要があるテストです。

オプション3「ダミーデータを使用したテストインスタンスのデプロイ」の方が優れています。しかし、テストをデプロイするための時間の有効利用になる場合は、同じテストをテストサーバーに向けることができるため、テストの記述には影響しません。

2
Ewan

これはAPIに依存しますが、可能であれば、オプション#3(プライベートテストインスタンス)を使用します。

あなたが言及した理由のために、APIのスタブ(オプション#1)は最悪のオプションであり、このルートに行くことはおそらく良い(多くの時間を浪費する)よりも害を及ぼします。

実際のAPI(オプション#2)に対して実行すると、テストが不安定になり、信頼性がなくなり、いくつかの誤検知の後、人々はそれらの使用を中止します。データが変更されるだけでなく、サービスも停止する可能性があります。私の意見では、これはクエリのテストがなく、問題を見つけるために統合/システムテストに依存しているのと同じです。つまり、APIデータがめったに変更されず、API自体がほぼ常に稼働している場合、これは実行可能なオプションになる可能性があります。ほとんどのAPIはこの説明に適合しません。

最終的には、これらのクエリの重要性と複雑さによって決まります。少数のクエリがあり、その一部が非常に複雑で、それらをテストする必要があると感じた場合は、テスト用のプライベートインスタンスを設定する労力を費やします。 。他の単体テストと同じように、採算が取れます。

0