Goでは、TCP接続(net.Conn)はio.ReadWriteCloserです。TCP接続をシミュレートしてネットワークコードをテストしたいと思います。私が持っている2つの要件があります:
- 読み取るデータは文字列に格納されます
- データが書き込まれるときはいつでも、後でアクセスできるある種のバッファにデータを保存したいのですが
このためのデータ構造、またはそれを作成する簡単な方法はありますか?
Goでは、TCP接続(net.Conn)はio.ReadWriteCloserです。TCP接続をシミュレートしてネットワークコードをテストしたいと思います。私が持っている2つの要件があります:
このためのデータ構造、またはそれを作成する簡単な方法はありますか?
編集:私はこの答えを少し簡単にするパッケージにまとめました-ここを参照してください:https ://github.com/jordwest/mock-conn
Ivanのソリューションは単純なケースでも機能しますが、実際のTCP接続は実際には2つのバッファー、つまりパイプであることに注意してください。例えば:
Server | Client
---------+---------
reads <=== writes
writes ===> reads
サーバーが読み取りと書き込みの両方を行う単一のバッファーを使用すると、サーバーがそれ自体と通信することになりかねません。
MockConn
タイプをReadWriteCloser
サーバーに渡すことができるソリューションは次のとおりです。、および関数は、サーバーのパイプの端にある関数にプロキシするだけですRead
。Write
Close
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)
}
}
質問されたときにこれが存在したかどうかはわかりませんが、相互にリンクされたnet.Pipe()
2つの全二重インスタンスを提供するものが必要になる可能性がありますnet.Conn
使ってみませんbytes.Buffer
か?これio.ReadWriter
はString
、保存されたデータを取得するためのメソッドです。にする必要がある場合はio.ReadWriteCloser
、独自のタイプを定義できます。
type CloseableBuffer struct {
bytes.Buffer
}
Close
メソッドを定義します。
func (b *CloseableBuffer) Close() error {
return nil
}
ほとんどの場合、net.Connをモックする必要はありません。
テストコードでは、反対側を模倣するゴルーチンをいつでも実行できます。