web-dev-qa-db-ja.com

Golangの単体テストでnet.Connをどのようにテストしますか?

私は現在、Goのnet.Connインターフェイス、およびその機能の上に構築される他の関数のユニットテストの作成を検討しています。GoogleGoでユニットテストを行うための最良の方法は何ですか。私のコードは次のようになります:

conn, _:=net.Dial("tcp", "127.0.0.1:8080")
...
fmt.Fprintf(conn, "test")
...
buffer:=make([]byte, 100)
conn.Read(buffer)

このコードとこれらの関数を使用してサーバーのように動作する別のゴルーチンを起動するコード、 net.http.httptest package などをテストする最も効率的な方法は何ですか?

20
ThePiachu

特定のケースの実装の詳細に依存しますが、一般的なアプローチは、サーバーを起動し(既に示唆したように、別のgoroutineで)、着信接続をリッスンすることです。

たとえば、サーバーを起動して、接続から読み取っているコンテンツが実際にクライアントから送信したものであることを確認します。

func TestConn(t *testing.T) {
    message := "Hi there!\n"

    go func() {
        conn, err := net.Dial("tcp", ":3000")
        if err != nil {
            t.Fatal(err)
        }
        defer conn.Close()

        if _, err := fmt.Fprintf(conn, message); err != nil {
            t.Fatal(err)
        }
    }()

    l, err := net.Listen("tcp", ":3000")
    if err != nil {
        t.Fatal(err)
    }
    defer l.Close()
    for {
        conn, err := l.Accept()
        if err != nil {
            return
        }
        defer conn.Close()

        buf, err := ioutil.ReadAll(conn)
        if err != nil {
            t.Fatal(err)
        }

        fmt.Println(string(buf[:]))
        if msg := string(buf[:]); msg != message {
            t.Fatalf("Unexpected message:\nGot:\t\t%s\nExpected:\t%s\n", msg, message)
        }
        return // Done
    }

}

ここでは、サーバーをgoroutineで起動していないことに注意してください。そうしないと、リスナーがテストを実行する前にテストケースが終了する可能性があります。

10
Iñigo

net.Pipe を使用すると、基本的に接続の両端が得られる可能性があります(.Accept()の後など)。

server, client := net.Pipe()
go func() {
  // Do some stuff
  server.Close()
}()

// Do some stuff
client.Close()
67
Freman

別のオプションは counterfeiter パッケージです。これにより、インターフェイスからモックを作成し、必要な呼び出しをすべてスタブ化できます。私はそれをスタブアウトに大成功で使用しましたnet.Conn protobufクライアントを Geode でテストしているインスタンス。

例- https://github.com/gemfire/geode-go-client/blob/master/connector/protobuf_test.go

2
Jens D