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

Multi tool use


How does one test net.Conn in unit tests in Golang?
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?
net
httptest
There are several libraries for mocking in unit testing, take a look at this post for hints stackoverflow.com/questions/19167970/mock-functions-in-golang
– PerroVerd
Jun 16 '15 at 8:33
3 Answers
3
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:tt%snExpected:t%sn", 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.
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()
This is the greatest answer for testing tcp connections without starting a server. Should be the accepted or at least more up-voted answer imho. Thank you!
– middlehut
Apr 1 '17 at 13:02
Yes, this is genius! You don't need the overhead of actually using TCP. You could in theory parallelize your tests running by using this design, since it does not reserve global ports from the oprating system.
– joonas.fi
Dec 5 '17 at 9:54
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.
net.Conn
For example - https://github.com/gemfire/geode-go-client/blob/master/connector/protobuf_test.go
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Suggest reading the source for the tests for the actual
net
library. I have picked up plenty of tips by doing that in the past. Secondly as you have already mentioned use thehttptest
package.– miltonb
Jun 7 '15 at 4:31