2017-01-19 21 views
1

BSDソケットを使用してUbuntuにサーバー/クライアントベースのC++アプリケーションを作成しています。私は単体テストフレームワークとしてGoogle C++ Test Frameworkを使用しています。BSDソケットをテストする方法

単体テストでサーバーとクライアントを作成する方法があるので、サーバーの受信/受信をテストし、両者の送受信をテストできますか?

問題は、ソケットの受け入れ(ポートを聞いた後)をサーバーでテストする場合、このテストでクライアントに接続するにはどうすればよいですか。同じTEST()(またはTEST_F())のスコープ内で、テスト対象のサーバにクライアントを接続させるためにマルチスレッドを使用できますか?

私はクライアントを作成してテスト中のサーバーに手動で接続できますが、自動ユニットテストの目的を無効にします。

私はGoogle Mockについて何かを読んでくれました。それは私の正気のチェック(どの機能が呼び出されているか、何回何回返されたか、など)を見ているようです。

ご協力ありがとうございます。

+1

ソケットの抽象化を作成し、それをクラスに挿入します。その後、あなたはそれを嘲笑することができます。 –

+0

@BartoszPrzybylskiあなたは私にいくつかの例を教えてくれますか?私は駆動開発をテストするために新しいです、そして、私はどのように注射を行うことができないのか分かりません。どうもありがとう。 – Joe

+0

TCP接続を表す抽象基本クラスを作成し、データの読み書きなどのメソッドを持ちます。その後、実動コードは実ソケットを使用してロジックを実装するクラスを派生させることができ、テストユニットはロジックを実装する別のクラス偽のデータを使用してすべての基本クラスインターフェイスを使用して残りのユニットコードを記述し、必要に応じて適切な派生クラスをインスタンス化できます。このようにして、実際のネットワーク動作をテストしていない限り、テスト中に実際のソケットを使用する必要はありません。 –

答えて

1

[OK]を、ネットワークソケットの抽象化の作成から始めましょう。システム関数への呼び出しを疑似できるようにするには、これが必要です。

class Socket { 
public: 
    virtual bool connect(const struct sockaddr *address, socklen_t address_len) = 0; 
    virtual Socket* accept(struct sockaddr *restrict address, socklen_t *restrict address_len) = 0; 
    /* more functions */ 
} 

それはsockaddrsocklen_tを使用しているため、上記のコードは、UNIXのクラスにコンテンツとそのバインドの抽象多くをされていません。このような何かを起動します。また、これらの2つのタイプにプラットフォームに依存しないコードを作成する抽象化を作成する必要がありますが、これは設計によって異なります。

実際のアプリケーションで使用するための具体的なTCP/UDPクラスを作成する必要はありません。

class TCPSocket : public Socket { 
public: 
    TCPSocket() { 
     socket_ = socket(PF_INET, SOCK_STREAM, 0); 
     if (socket_ == -1) { 
      /* handle errors */ 
     } 
    } 
    TCPSocket(int sock) : socket_(sock) {} 
    bool connect(const struct sockaddr *address, socklen_t address_len) override { 
     return connect(socket_, address, address_len) == 0; 
    } 
    Socket* accept(struct sockaddr *restrict address, socklen_t *restrict address_len) override { 
     int s = accept(socket_, address, address_len); 
     if (s == -1) { 
      /* handle errors */ 
     } 
     return new TCPSocket(s); 
    } 
private: 
    int socket_; 
} 

Phew :)あなたのクラスに移動しましょう。

あなたのクラスの名前はAとし、methodのテスト方法があるとします。 クラスはコンストラクタ内でSocket*のいずれかを取るか、methodはパラメータとしてSocket*を取る必要があります。次に、テストコードでモックを指定することができます。

class MockSock : public Socket { 
public:   
    MOCK_METHOD2(connect, bool(const struct sockaddr*, socklen_t)); 
    MOCK_METHOD2(accept, Socket*(struct sockaddr*, socklen_t*)); 
} 

は、ちょうどMockSockをインスタンス化し、適切なEXPECT_CALL値でAまたはmethodに渡します。

+0

本当にありがとうございますが、私は受け入れを呼び出すときにクライアントに接続する必要があります。それ以外の場合は、タイムアウトやクライアントが接続していない場合は受け入れがブロックされます。単体テストを使ってどのように達成できますか? – Joe

+0

@Joeソケットに接続するためのクライアントは必要ありません。それは嘲笑の全体の点です。 GMockはあなたが彼に言いたいことをするでしょう、そうするよう指示する必要があります。そのため、システム関数を呼び出すことを避けるために抽象化が導入されています。 –

+0

したがって、私は実際のソケット受け入れ関数をテストしていないことを意味しますが、このサブルーチン内の他のロジック(acceptに追加した場合)とシステムの動作(つまり、この関数が必要なときに呼び出されたかどうかなど) – Joe

関連する問題