8

Goでは、TCP接続(net.Conn)はio.ReadWriteCloserです。TCP接続をシミュレートしてネットワークコードをテストしたいと思います。私が持っている2つの要件があります:

  1. 読み取るデータは文字列に格納されます
  2. データが書き込まれるときはいつでも、後でアクセスできるある種のバッファにデータを保存したいのですが

このためのデータ構造、またはそれを作成する簡単な方法はありますか?

4

4 に答える 4

5

編集:私はこの答えを少し簡単にするパッケージにまとめました-ここを参照してください:https ://github.com/jordwest/mock-conn


Ivanのソリューションは単純なケースでも機能しますが、実際のTCP接続は実際には2つのバッファー、つまりパイプであることに注意してください。例えば:

 Server   |   Client
 ---------+---------
  reads <===  writes
 writes ===>  reads

サーバーが読み取りと書き込みの両方を行う単一のバッファーを使用すると、サーバーがそれ自体と通信することになりかねません。

MockConnタイプをReadWriteCloserサーバーに渡すことができるソリューションは次のとおりです。、および関数は、サーバーのパイプの端にある関数にプロキシするだけですReadWriteClose

type MockConn struct {
    ServerReader *io.PipeReader
    ServerWriter *io.PipeWriter

    ClientReader *io.PipeReader
    ClientWriter *io.PipeWriter
}

func (c MockConn) Close() error {
    if err := c.ServerWriter.Close(); err != nil {
        return err
    }
    if err := c.ServerReader.Close(); err != nil {
        return err
    }
    return nil
}

func (c MockConn) Read(data []byte) (n int, err error)  { return c.ServerReader.Read(data) }
func (c MockConn) Write(data []byte) (n int, err error) { return c.ServerWriter.Write(data) }

func NewMockConn() MockConn {
    serverRead, clientWrite := io.Pipe()
    clientRead, serverWrite := io.Pipe()

    return MockConn{
        ServerReader: serverRead,
        ServerWriter: serverWrite,
        ClientReader: clientRead,
        ClientWriter: clientWrite,
    }
}

「サーバー」接続をモックするときは、使用する場所の代わりにMockConnを渡すだけですnet.Conn(これは明らかにインターフェイスのみを実装します。完全なインターフェイスをサポートする必要がある場合は、etcReadWriteCloserのダミーメソッドを簡単に追加できます)LocalAddr()net.Conn

ClientReaderテストでは、必要に応じてフィールドとClientWriterフィールドを読み書きすることにより、クライアントとして機能できます。

func TestTalkToServer(t *testing.T) {
    /*
     * Assumes that NewMockConn has already been called and
     * the server is waiting for incoming data
     */

    // Send a message to the server
    fmt.Fprintf(mockConn.ClientWriter, "Hello from client!\n")

    // Wait for the response from the server
    rd := bufio.NewReader(mockConn.ClientReader)
    line, err := rd.ReadString('\n')

    if line != "Hello from server!" {
        t.Errorf("Server response not as expected: %s\n", line)
    }
}
于 2015-06-23T08:12:21.600 に答える
5

質問されたときにこれが存在したかどうかはわかりませんが、相互にリンクされたnet.Pipe()2つの全二重インスタンスを提供するものが必要になる可能性がありますnet.Conn

于 2015-11-29T18:58:14.953 に答える
4

使ってみませんbytes.Bufferか?これio.ReadWriterString、保存されたデータを取得するためのメソッドです。にする必要がある場合はio.ReadWriteCloser、独自のタイプを定義できます。

type CloseableBuffer struct {
    bytes.Buffer
}

Closeメソッドを定義します。

func (b *CloseableBuffer) Close() error {
    return nil
}
于 2009-12-30T17:39:52.127 に答える
0

ほとんどの場合、net.Connをモックする必要はありません。

テストコードでは、反対側を模倣するゴルーチンをいつでも実行できます。

于 2020-10-03T16:01:23.600 に答える