如何在Golang的单元测试中测试net.Conn?

huangapple go评论99阅读模式
英文:

How does one test net.Conn in unit tests in Golang?

问题

我目前正在研究如何为Go语言中的net.Conn接口创建一些单元测试,以及构建在该功能之上的其他函数,我想知道在Google Go中进行单元测试的最佳方法是什么?我的代码如下:

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

对于测试这段代码和使用这些函数的代码,最有效的方法是启动一个单独的goroutine来充当服务器,使用net/http/httptest包,或者其他方法吗?

英文:

I'm currently looking into creating some unit tests for net.Conn interface in Go, as well as other functions that build up on top of that functionality, and I'm wondering what is the best way to unit test that in Google Go? My code looks like:

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

Is the most efficient way of testing this code and the code that uses these functions to spin up a separate goroutine to act like the server, use net.http.httptest package, or something else?

答案1

得分: 127

你可以尝试使用net.Pipe来实现你所需的功能,它基本上提供了连接的两端(类似于.Accept()之后的情况)。

server, client := net.Pipe()
go func() {
  // 做一些操作
  server.Close()
}()

// 做一些操作
client.Close()
英文:

You might be able to do what you need with net.Pipe which basically gives you both ends of a connection (think, after .Accept())

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

// Do some stuff
client.Close()

答案2

得分: 14

尽管具体情况取决于你的实现细节,但一般的方法是启动一个服务器(在一个单独的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中启动服务器,否则测试用例很可能在监听器运行测试之前就已经完成了。

英文:

Although it will depend on the implementation details of your particular case, the general approach will be to start a server (in a separate goroutine, as you already hinted), and listen to the incoming connections.

For example, let's spin up a server and verify that the content we are reading from the connection is indeed the one we send over from the client:

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
	}

}

Note that here I'm not starting the server in the goroutine, as otherwise the test case is likely to be finished before the listener has run the test.

答案3

得分: 2

另一个选择是counterfeiter包,它允许你从接口创建模拟对象,然后你可以对需要的调用进行存根处理。我曾经非常成功地使用它来对net.Conn实例进行存根处理,这是我在测试Geode的protobuf客户端时使用的。

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

英文:

Another option is the counterfeiter package which lets you create mocks from interfaces and then you can stub out whatever calls you need. I have used it with great success to stub out net.Conn instances where I am testing out a protobuf client for Geode.

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

huangapple
  • 本文由 发表于 2015年6月7日 07:49:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/30688685.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定