ドキュメントをAmazon S3にアップロードするメソッドのテストに苦労していますが、この質問は重要なAPI /外部依存関係に当てはまると思います。考えられる解決策は3つだけですが、どれも満足できるようには見えません。
コードを実行し、実際にドキュメントをアップロードし、アップロードされていることをAWSのAPIで確認し、テストの最後に削除します。これにより、テストが非常に遅くなり、テストが実行されるたびに費用がかかり、常に同じ結果が返されなくなります。
モックS3。そのオブジェクトの内部について私は何も知らないので、これは非常に毛深いです、そしてそれはあまりに複雑であるのでそれは間違っていると感じます。
MyObject.upload()が正しい引数で呼び出されていることを確認し、S3オブジェクトを正しく使用していることを確認してください。テストだけでS3 APIを正しく使用したことを確認する方法がないので、これは私を悩ませます。
Amazonがどのようにして独自のSDKをテストするかを確認しました。彼らはモックを行う200行のヘルパーを持っています。同じことをするのは現実的ではないと思います。
どうすればこれを解決できますか?
ここで注意しなければならない2つの問題があります。
1つ目は、すべてのテストを単体テストの観点から見ているように見えることです。単体テストは非常に価値がありますが、唯一の種類のテストではありません。テストは実際には、非常に高速な 単体テスト から低速な 統合テスト からさらに低速な 受け入れテスト まで、いくつかの異なるレイヤーに分割できます。 ( 機能テスト のように、さらに多くのレイヤーが分割される可能性があります。)
2つ目は、サードパーティコードへの呼び出しとビジネスロジックを混在させ、テストの課題を作成し、コードをより脆弱にすることです。
単体テストは高速で、頻繁に実行する必要があります。依存関係のモックは、これらのテストの実行を高速に保つのに役立ちますが、依存関係が変更されてモックが変更されない場合、カバレッジに穴が生じる可能性があります。テストがまだ正常に実行されている間、コードが壊れる可能性があります。一部のモックライブラリは、依存関係のインターフェイスが変更された場合に警告を出しますが、他のライブラリはできません。
一方、統合テストは、サードパーティのライブラリを含むコンポーネント間の相互作用をテストするように設計されています。実際のオブジェクトがどのように相互作用するかを見たいので、モックはこのレベルのテストでは使用しないでください。実際のオブジェクトを使用しているため、これらのテストは遅くなり、単体テストほど頻繁には実行されません。
受け入れテストは、さらに高いレベルを調べ、ソフトウェアの要件が満たされていることをテストします。これらのテストは、展開される完全なシステム全体に対して実行されます。繰り返しますが、モッキングは使用しないでください。
モックに関して価値があるとわかったガイドラインの1つは 所有していないモックタイプではない です。 AmazonはS3のAPIを所有しているため、その下で変更されないことを確認できます。一方、あなたにはこれらの保証はありません。したがって、テストでS3 APIをモックアウトすると、コードが変更されて破損する可能性がありますが、テストはすべて緑色で表示されます。では、サードパーティのライブラリを使用するコードを単体テストするにはどうすればよいでしょうか。
まあ、私たちはしません。ガイドラインに従えば、所有していないオブジェクトをモックすることはできません。 しかし…直接的な依存関係を所有している場合、それらをモックアウトできます。しかし、どうやって? S3 APIの独自のラッパーを作成します。 S3 APIによく似たものにしたり、ニーズにより近いものにすることができます(推奨)。 _AmazonS3Bucket
_ではなくPersistenceService
のように、少し抽象化することもできます。 PersistenceService
は#save(Thing)
や#fetch(ThingId)
などのメソッドとのインターフェースになります。これは、表示したいメソッドのタイプです(これらは例であり、実際には異なるメソッドが必要になる場合があります)。 。これで、S3 API(_S3PersistenceService
_など)の周囲にPersistenceService
を実装して、呼び出し元のコードからカプセル化することができます。
次に、S3 APIを呼び出すコードに移ります。これらの呼び出しをPersistenceService
オブジェクトの呼び出しに置き換える必要があります。 依存性注入 を使用して、PersistenceService
をオブジェクトに渡します。 _S3PersistenceService
_を要求することは重要ですが、PersistenceService
を要求することは重要です。これにより、テスト中に実装を交換できます。
S3 APIを直接使用していたすべてのコードがPersistenceService
を使用し、_S3PersistenceService
_がS3 APIへのすべての呼び出しを行うようになりました。テストでは、PersistenceService
を所有しているのでモックアウトし、モックを使用してコードが正しい呼び出しを行うことを確認します。しかし、これで_S3PersistenceService
_のテスト方法が残ります。これには以前と同じ問題があります。外部サービスを呼び出さずに単体テストを行うことはできません。ですので、単体テストは行いません。私たちはS3 APIの依存関係を模倣することができましたが、これは私たちにほとんどまたはまったく追加の自信を与えません。代わりに、統合テストというより高いレベルでテストする必要があります。
これは、コードの一部を単体テストするべきではないと言って少し厄介に聞こえるかもしれませんが、達成したことを見てみましょう。 PersistenceService
を使用して単体テストできるように、単体テストができなかった場所にコードがたくさんありました。サードパーティのライブラリの混乱は、単一の実装クラスに限定されています。そのクラスは、APIを使用するために必要な機能を提供する必要がありますが、外部ビジネスロジックがアタッチされていません。したがって、いったん作成すると、非常に安定していて、あまり変化しないはずです。コードが安定しているため、それほど頻繁に実行しない遅いテストを信頼できます。
次のステップは、_S3PersistenceService
_の統合テストを記述することです。これらは名前またはフォルダで区切る必要があるため、高速な単体テストとは別に実行できます。統合テストでは、コードが十分な情報を提供している場合、単体テストと同じテストフレームワークを使用できることが多いため、新しいツールを学ぶ必要はありません。統合テストの実際のコードは、オプション1用に作成するコードです。
両方を行う必要があります。
実行、アップロード、削除は統合テストです。これは外部システムとのインターフェースであるため、動作が遅くなることが予想されます。ローカルで行うすべてのビルドの一部ではないはずですが、CIビルドまたはナイトリービルドの一部である必要があります。これにより、これらのテストの遅さが相殺され、それでも自動的にテストすることの価値が提供されます。
また、より迅速に実行される単体テストも必要です。外部システムに過度に依存しないことが一般的に賢明であるため(実装を交換したり切り替えたりできる)、コード化できるS3を介した単純なインターフェースを試してみてください。ユニットテストでそのインターフェースのモックを作成して、ユニットテストをすばやく実行できるようにします。
最初のテストでは、コードが実際にS3で動作することを確認し、2番目のテストでは、コードがS3と通信するコードを正しく呼び出すことを確認します。
これは、APIの使用の複雑さに依存します。
S3 APIを実際に呼び出し、エンドツーエンドで機能することを確認する少なくともいくつかのテストを必ず行う必要があります。
また、APIを実際に呼び出さない追加のテストを必ず行う必要があるため、常にAPIを呼び出すことなく、独自のソフトウェアを適切にテストできます。
残っている質問は次のとおりです:APIをモックする必要がありますか?
そして、それはあなたがどれだけそれを使うかに依存すると思います。 1つまたは2つの単純なアクションのみを実行している場合は、モックアップのすべての問題に進む必要はないと思います。関数の使用状況を確認し、ライブテストを行うだけで十分です。
ただし、使用がより複雑で、結果に影響を与える可能性のあるさまざまなシナリオやさまざまな変数がある場合は、より完全なテストを行うために、モックアップする必要があるでしょう。
以前の回答に加えて、主な質問は、テスト用にS3 APIをモックするかどうか(および方法)です。
個々のS3応答を手動でモックする代わりに、非常に洗練された既存のモックフレームワークを利用できます。たとえば moto は、実際のS3 APIと非常によく似た機能を提供します。
LocalStackもご覧ください。既存のツールを組み合わせ、完全に機能するローカルクラウド環境( S3)統合テストを容易にします。
これらのツールの一部は他の言語(Python)で記述されていますが、Java/JUnitなどのテストから外部プロセスでテスト環境を立ち上げるのは簡単です。