最終的に一貫したサービスに対するテストを作成するにはどうすればよいですか?


17

Google App Engine Datastoreの上にサービスを構築しています。これは最終的に一貫したデータストアです。私のアプリケーションでは、これで問題ありません。

ただし、PUTオブジェクトのようなことをしてからオブジェクトを取得し、返されたオブジェクトのプロパティをチェックするテストを開発しています。残念ながら、データストアは最終的に一貫しているため、これらの簡単なテストは再現できません。

最終的に一貫したサービスをどのようにテストしますか?


2
そもそも、外部サービスに対する再現性を期待してテストするのはなぜですか?

...そして実際に何をテストしようとしていますか?あなたのコード?またはGoogleの?

5
システム全体をテストしています。つまり、それらは統合テストであり、単体テストではありません。
ダグリチャードソン

3
How can I reproducibly test an eventually consistent service? -できません。「再現可能」という単語または「最終的に」という単語を削除する必要があります。あなたは両方を持つことはできません。
ロバートハーヴェイ

1
再現性があるかどうかにかかわらず、最終的に一貫性があれば、結果は成功します。あなたはすでにそれがあなたのアプリにとって良いことだと言ったので、あなたは本当に何をテストしていますか?偶然?GAEとの統合?あなたのコード?
Laiv

回答:


16

機能テストを設計するときは、非機能要件を考慮してください-サービスに「x(秒/分/など)内で一貫した」という非機能要件がある場合、PUT要求を実行し、xを待機してからGET要求を実行します。

その時点で、データがまだ「到着」していない場合は、PUT要求が要件に適合していないと見なすことができます。


7

テストを高速で一貫性のあるものにしたいのです。最終的な一貫性のためにときどき失敗する可能性のあるテストの作成を開始する場合、失敗したテストを無視しますが、それはどのような用途ですか?

PUTおよびGETリクエストを処理する偽サービスを作成しますが、一貫性を保つために追加の操作があります。テストは次のとおりです。

datastore.do_put(myobj);
datastore.make_consistent();
validate(datastore.do_get(), myobj);

これにより、GETがPUTオブジェクトを正常に取得したときに、ソフトウェアの動作をテストできます。また、サービスがまだ一貫していないためにGETがオブジェクト(または正しいオブジェクト)を見つけられない場合に、ソフトウェアの動作をテストすることもできます。への呼び出しを省略しmake_consistent()ます。

実際のサービスと相互作用するテストを行う価値はありますが、通常の開発ワークフローの外で実行する必要があります。100%の信頼性は決してありません(たとえば、サービスがダウンした場合)。これらのテストは次の目的で使用する必要があります。

  1. PUTと後続のGETの間の平均および最悪のケース時間のメトリクスを提供し、一貫性を保ちます。そして
  2. 偽のサービスが実際のサービスと同様に動作することを確認します。https://codewithoutrules.com/2016/07/31/verified-fakes/を参照してください

6

OK 「何をテストしていますか」が重要な質問です。

  • 私は、グーグルのものが機能すると仮定して何が起こるかの私の内部ロジックをテストしています

この場合、Googleサービスをモックし、常に応答を返す必要があります。

  • 私はGoogleが生成することがわかっている一時的なエラーに対処できるロジックをテストしています

この場合、Googleサービスをモックし、正しい応答の前に常に一時的なエラーを返す必要があります

  • 私の製品が実際のGoogleサービスで実際に動作することをテストしています

実際のGoogleサービスを注入して、テストを実行する必要があります。だが!テストするコードには、一時的なエラー処理(再試行)が組み込まれている必要があります。したがって、一貫した応答を取得する必要があります。(Googleの動作が非常に悪い場合を除く)


モックの提案に対して+1-可能であれば、追加のオプションに対してより多くの賛成票を投じます。
mcottle

6

次のいずれかを使用します。

  • PUTの後、成功するまでGETをN回再試行します。N回試行しても成功しなかった場合は失敗します。
  • PUTとGETの間のスリープ

残念ながら、これらの手法の両方でマジック値(Nまたはスリープ期間)を選択する必要があります。


1
あなたは明確にすることができます:これらの選択肢は、補完的なものですか?私はあなたがそれらが選択肢であると言うことを意味すると思う-そしてそれは私がそれらをどう思うかです。しかし、多分私は間違っています。
ロビングリーン

1
正しい、私はそれらが選択肢であることを意味しました。
ダグリチャードソン

2

私が理解しているように、Google Cloudデータストアでは、強く一貫したクエリと最終的に一貫したクエリの両方が可能です

トレードオフは、非常に一貫性のあるクエリがかなり厳しいレート制限(テスト中に共存できるもの)であることです。

可能性の1つは、クエリをラッパー内のデータストアに配置して、テスト目的で強力な一貫性を実現することです。

たとえば、start_debug_strong_consistency()およびというメソッドを使用できますend_debug_strong_consistency()

startメソッドは、後続のすべてのクエリの祖先キーとして使用できるキーを作成し、endメソッドはキーを削除します。

テストしている実際のクエリへの唯一の変更は、setAncestor(your_debug_key)そのキーが存在する場合に呼び出すことです。


1

理論的には良いが、常に実用的ではないかもしれないアプローチの1つは、テスト中のシステムですべての書き込み操作をべき等性にすることです。つまり、テストコードが固定された順番で物事をテストすると仮定すると、期待する結果が得られるまですべての読み取りすべての書き込みを個別に再試行でき、テストコードで定義したタイムアウトを超えるまで再試行できます。つまり、結果がB1になるまでA1を実行し、必要に応じて再試行します。次に、結果がB2になるまでA2を実行します。

そうすれば、書き込み操作の前提条件をわざわざチェックする必要はありません。書き込み操作が既にそれらをチェックしているので、成功するまで再試行するだけです!

同じ「デフォルト」タイムアウトを可能な限り使用します。これは、システム全体が遅くなった場合に増やすことができ、特に遅い操作を再試行するときにデフォルトを個別にオーバーライドできます。


1

Google App Engine Datastoreなどのサービスは、複数のグローバルに広がるPoint of Presence(POP)にわたるデータ複製に基づいています。最終的に一貫したサービスの統合テストは、実際には、POPのセット全体でのそのサービスのレプリケーション率のテストです。コンテンツが特定のサービスのすべてのPOPに拡散する速度は、複製方法やさまざまなインターネットトランスポートの問題など、いくつかの要因によってはサービス内のすべてのPOPと同じになるわけではありません。これらは2つの例です最終的に一貫性のあるデータストアサービスのレポートの大部分を占めています(少なくとも、主要なCDNで働いていたときの経験です)。

特定のプラットフォームでオブジェクトの複製を効果的にテストするには、テストを設定して、特にサービスの各POPから同じ最近配置されたオブジェクトを要求する必要があります。POPリストを1〜5回、またはPOPリスト内のすべてのPOPがオブジェクトを含むレポートになるまでテストすることをお勧めします。以下は、自由に調整できるテストを実行する一連の間隔です。データストアに配置してから1、5、60分、12時間、25時間。重要なのは、オブジェクトをグローバルにレプリケートする特定のサービスの機能を把握するために、後で確認および分析するために各間隔で結果を記録することです。多くの場合、データストアサービスは、ローカルコピーがローカルに要求された後にローカルコピーをPOPにプルするだけです[ルーティングはBGPプロトコルを介して行われるため、特定のプラットフォームでグローバルに有効になるためにテストは特定の各POPからオブジェクトを要求する必要があります] 。Googleのデータストアの場合、「33か国で70か所以上のプレゼンス」から特定のオブジェクトを照会するためのテストのセットアップを見ています。GoogleサポートからPOP固有のアドレスURLリストを取得する必要があるでしょう[ref:https://cloud.google.com/about/locations/ ]またはGoogleがレプリケーションにFastlyを使用している場合、Fastlyサポート[ https://www.fastly.com/resources ]。

この方法の利点は次のとおりです。1)特定のサービスのレプリケーションプラットフォームの感覚をつかみ、全体的な強さおよび弱点を(統合テスト中のように)グローバルに把握します。2)テストするオブジェクトには、コンテンツをウォームするためのツールがあります[特定のローカルPOPでコピーを作成する最初のリクエストを作成]-クライアントがリクエストする前にコンテンツがグローバルに拡散する方法を提供します地球上のどこでも。


0

Google App Engine Datastoreの経験があります。驚くべきことに、ローカルで実行すると、「一貫性」よりも「最終的に」多くなります。最も単純な例:新しいエンティティを作成してから取得します。多くの場合、過去5年間で、ローカルで実行されているSDKが新しいエンティティをすぐに検出するのではなく、約0.5秒後に検出するのを見てきました。

ただし、実際のGoogleサーバーに対して実行した場合、その動作は見ていません。データストアクライアントが常に同じ側のサーバーに対して実行されるようにしようとするため、通常、変更はすぐにクエリ反映されます。

統合テストに関する私のアドバイスは、実サーバーに対して実行することです。そうすれば、おそらく、結果を得るために偽のポーリングや遅延をかける必要はないでしょう。


これは便利ですが、統合テストで複数のアプリケーションサーバーに関連するわずかな破損が検出されない可能性があります。正当な理由で、ローカルサーバーが最終的に一貫したものになったと思います。
ロビングリーン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.