何をテストするか
すべての単体テスト戦略の一般的な目標は次のとおりです。
- 完全なコード カバレッジ: アプリケーションのコードの各行が、完全なテスト スイート中に少なくとも 1 回実行されることを意味します。
- 仕様の完全な網羅: 通常、ソフトウェア開発は、ソフトウェアが何を行い、考えられる各シナリオでどのように反応するかを正確に記述した機能仕様から始まります。仕様に記載されている各要件には、少なくとも 1 つのテストが必要です。仕様がない場合、最小限のテストのガイドラインは、HTTP プロトコル自体の仕様になる可能性があります。
サーバー アプリケーションをテストするときはいつでも、クライアントが HTTP プロトコルの完全な実装であると仮定することはできないことに留意する必要があります。現実の世界では、サーバーは、それを間違って実装したり、アプリケーションの任意の状態で突然終了した信頼性の低い接続を持つクライアントに直面したりします。また、サーバーの脆弱性を意図的に見つけて悪用しようとする悪意のあるクライアントについても説明していません。これらは、テストケースが必要な状況でもあります。
多くの場合、サーバーはマルチスレッドです。つまり、マルチスレッドに伴う通常の問題 (競合状態、デッドロック、同期の問題、ビジー スピンなど) をテストする必要があります。残念ながら、これらの問題は予測が難しく、意味のある単体テストを作成するのはさらに困難です。これらの問題は、通常、単体テストではなく、統合テストとシステム テストの範囲である、さまざまなコンポーネントの相互作用を通じて明らかになるという理由だけではありません。
テスト方法
単体テストは通常、外部リソースに依存するべきではありません。依存する場合、独自のアプリケーションではなく、そのリソースをテストしているためです。http サーバーの場合のように、アプリケーションの機能が外部システムに大きく依存している場合は、他のシステムをシミュレートする必要があります。
これは、外部リソースをモック オブジェクトで実装することによって行われます。モック オブジェクトは、外部リソースに依存するオブジェクトの代わりをするオブジェクトです (外部リソースを拡張するか、同じインターフェイスを実装することにより) が、その動作をシミュレートするだけです。Web サーバーのコンテキストでは、Socketを拡張するクラスを作成しますが、実際にネットワークにアクセスせずに外部クライアントをシミュレートするもので Socket のすべてのメソッドをオーバーライドします。
次に、これを使用して、単体テスト中に通常のソケットの代わりにクラスをテストします。
これにより、応答が遅い、非常に速い、または単に間違っているクライアントなど、特別なテスト条件をテストするための特別なモック ソケットを簡単に実装できます。
new Socket()
「しかし、テストしたいクラスの内部を作成するとき、これをどのように行うべきか」と疑問に思うかもしれません。答えは、アプリケーションを単体テスト可能にするために、これを行うべきではないということです。キーワードはDependency Injectionです。一言で言えば、依存性注入とは、クラスがnew
その種類のクラスの Factory または Builder でない限り、クラスがキーワードを使用してはならないことを意味します。クラスによって使用されるオブジェクトは、それによって作成されるべきではありません。それらは、コンストラクターまたはセッター メソッドを使用して提供する必要があります。
例:
そのためConnectionListener
、 を使用してクライアントが接続するのを待機し、クライアントに対して何かを行うクラスがあるServerSocket
場合、コンストラクターでその ServerSocket を作成しないでください。その代わりに、ServerSocket を ConnectionListener のコンストラクターに渡す必要があります。製品コードでは、これは通常のサーバー ソケットになります。しかし、単体テストでは、ServerSocket を拡張するモック オブジェクトを渡すことができます。このモック オブジェクトは、1 つ以上のクライアントをシミュレートし、ConnectionListener が期待どおりに動作したかどうかを単体テスト フレームワークに報告します。