web-dev-qa-db-ja.com

ネットワーククライアントの単体テストを作成する方法

シンプルなhttpクライアントを作成する必要があります。私のクラスの単体テストがあると素晴らしいでしょう。しかし、私は適切でテスト可能なクラスを書く方法を知りません。

たとえば、次のようなクライアントがあります。

class HTTPClient
{
public:
     HTTPCLient(const std::string& Host, const std::string& port): session(Host, port) {}

     void send()
     {
         session.sendRequest(someRequest);
         Response response = session.receiveResponse();
         // ...
     }

private:
    SomeLibrary::ClientSession session;
};

sendメソッドをテストする方法(本当に欲しいものを送信する)?あざけることはできません。 HTTPClientが受け取るSomeLibrary::ClientSessionコンストラクター内のオブジェクト(テストではモックを渡します)が良い設計ですか?セッション等の実装の仕方は自分のクラスに隠しておくべきだと思います。

何か考えはありますか?

4
pawell55555

はい、セッションの実装への直接の依存関係を壊して、代わりにそれを注入するのは良い設計でしょう。 (テスト目的だけではありません。)

template <typename SessionT>
class HTTPClient
{
private:

  SessionT session_ {};

public:

  HTTPClient(SessionT session) : session_ {std::move(session)}
  {
  }

  // Optional convenience overload
  HTTPClient(const std::string& Host, const int port) : session_ {Host, port}
  {
  }

  void
  send()
  {
    this->session_.sendRequest(someRequest);
    auto response = this->session_.receiveResponse();
    // …
  }

};

応答タイプにautoを使用していることに注意してください。または、SessionTが適切なネストされたtypedefを提供することを要求します。

using ResponseT = typename SessionT::response_type;

templatesを使用したくない場合は、virtualインターフェースをセッションclassに定義し、スマートポインターを介して使用する必要があります。 templateを使い続けることをお勧めします。

この一般化には、単体テスト以外の目的があることに注意してください。たとえば、別のライブラリを試す、別のTLS実装でHTTPSを使用する、UNIXドメインソケットを介してローカルサーバーに接続する、パイプのペアを介してサーバープロセスと通信する、またはクライアントとサーバーを同じプロセスに実装することもできます。 、メッセージキューを介して通信します。これらのオプションのすべてが今日あなたに関連すると思われるかもしれませんが、柔軟性を持っていることは良いことです。

ちなみに、実際の「セッション」は「つながり」ではないでしょうか?

4
5gon12eder

送信方法をテストする方法(本当に私が欲しいものを送信すること)?私はそれをあざけることができません。 HTTPClientがSomeLibrary :: ClientSessionオブジェクトをコンストラクターで受け取ることを記述できます(テストではモックを渡します)が、それは優れた設計ですか?

はい。接続/セッションをクライアントに確実に注入する必要があります。

セッション等の実装の仕方は自分のクラスに隠しておくべきだと思います。

多分;必要な場合は、HttpClientを3つに分割します。

  • セッションタイプのテンプレートとしてのクライアント実装クラス:

    template <typename SessionT>
    class HTTPClientImpl { /* injected session, see @5gon12eder's answer */... };
    
  • セッション実装。

  • すべてをまとめた非常にシンクライアント:

    class HttpClient: private HTTPClientImpl<SessionT> // session type is now
                                                       // an implementation detail,
                                                       // invisible outside of HttpClient
    {
    };
    

    このクラスはテストされません。代わりに、実装クラスをテストしてください。

クラスのテスト可能性については、実際のネットワーク接続とモックサーバー(ハードコードされたコンテンツを提供する)でテストする必要があります。これが HTTPサーバー実装のサンプル ;です。コードを取得してビルドに統合し、定義済みの応答を返すアクティブなオブジェクト(サーバーをバックグラウンドで実行している)に変更するには、1日もかかりません。このようなアクティブなオブジェクトを使用すると、さまざまなサーバー応答を含む複数の単体テストをすばやく作成できます。

これを行うと、ネットワークトラフィックなしではモックやシミュレーションが困難な多くのエラーが発生します(たとえば、現在のネットワークトラフィックに応じて、より大きなメッセージがデータチャンクに非決定的に広がる)。

0
utnapistim