在Go中,TCP连接(net.Conn)是io.ReadWriteCloser.我想通过模拟TCP连接来测试我的网络代码.我有两个要求:
是否有一个数据结构,或一个简单的方法来制作一个?
编辑:我把这个答案推到了一个让事情变得更简单的软件包 - 请看这里:https://github.com/jordwest/mock-conn
虽然Ivan的解决方案适用于简单的情况,但请记住,真正的TCP连接实际上是两个缓冲区,或者说是管道.例如:
Server | Client
---------+---------
reads <=== writes
writes ===> reads
Run Code Online (Sandbox Code Playgroud)
如果您使用服务器读取和写入的单个缓冲区,您最终可能会与服务器通信.
这是一个允许您将MockConn类型作为a 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,
}
}
Run Code Online (Sandbox Code Playgroud)
在模拟'服务器'连接时,只需传递MockConn代替您将使用的位置net.Conn(这显然ReadWriteCloser只实现了接口,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)
}
}
Run Code Online (Sandbox Code Playgroud)
小智 4
为什么不使用bytes.Buffer?它是一个io.ReadWriter并且有一个String方法来获取存储的数据。如果您需要将其设为io.ReadWriteCloser,您可以定义自己的类型:
type CloseableBuffer struct {
bytes.Buffer
}
Run Code Online (Sandbox Code Playgroud)
并定义一个Close方法:
func (b *CloseableBuffer) Close() error {
return nil
}
Run Code Online (Sandbox Code Playgroud)