英文:
Testing constructors in Go
问题
我如何测试Client
结构体中的NewClient
构造函数?
package busybus
import (
"bufio"
"net"
)
type Client struct {
counter int
conn net.Conn
bufin *bufio.Reader
bufout *bufio.Writer
messages chan string
state string
}
func NewClient(conn net.Conn, messages chan string) *Client {
return &Client{
counter: 0,
conn: conn,
bufin: bufio.NewReader(conn),
bufout: bufio.NewWriter(conn),
messages: messages,
state: "waiting",
}
}
我尝试了以下测试:
package busybus
import (
"net"
"testing"
)
func TestNewClient(t *testing.T) {
ln, _ := net.Listen("tcp", ":65535")
conn, _ := ln.Accept()
messages := make(chan string)
client := NewClient(conn, messages)
if client.conn != conn {
t.Errorf("NewClient(%q, %q).conn == %q, want %q", conn, messages, client.conn, conn)
}
}
但是由于ln.Accept
导致测试运行时挂起,这似乎是完全错误的方法... 有什么建议可以测试这个构造函数吗?
英文:
How I can test my NewClient
constructor for my Client
struct ?
package busybus
import (
"bufio"
"net"
)
type Client struct {
counter integer
conn net.Conn
bufin *bufio.Reader
bufout *bufio.Writer
messages chan string
state string
}
func NewClient(conn net.Conn, messages chan string) *Client {
return &Client{
counter: 0,
conn: conn,
bufin: bufio.NewReader(conn),
bufout: bufio.NewWriter(conn),
messages: messages,
state: "waiting",
}
}
I tried some testing like this:
package busybus
import (
"net"
"testing"
)
func TestNewClient(t *testing.T) {
ln, _ := net.Listen("tcp", ":65535")
conn, _ := ln.Accept()
messages := make(chan string)
client := NewClient(conn, messages)
if client.conn != conn {
t.Errorf("NewClient(%q, %q).conn == %q, want %q", conn, messages, client.conn, conn)
}
}
But this hangs during the test runs due to ln.Accept
, it seems a totally wrong approach anyway... any suggestion how I can test this constructor ?
答案1
得分: 7
有些代码非常简短和简单,以至于确保测试的正确性比确保代码本身的正确性更加复杂。你的构造函数就是这样的代码。
我会做的是要么不进行任何测试,要么只是调用它(使用一些虚拟的net.Conn
实现)来确保在调用时不会出错(因此称为烟雾测试)。
稍后,您可以将其作为更大的测试(集成测试)的一部分进行测试,其中您有一个真实的服务器进行连接,并使用您的客户端结构与其通信。
如果您发现由于这个构造函数而导致的错误,那么首先添加一个演示问题的测试,然后修复它。然后你就有了你的测试
一个测试应该检查构造函数“按预期工作”。检查client.conn
的值几乎不检查任何预期行为,因为未导出字段的值不是行为。它只检查结构体和构造函数的实现方式,而不是实现的内容。测试“是什么”,而不是“怎么样”。
顺便说一下,您可以在客户端中嵌入一个*ReadWriter。
client.buf = bufio.NewReadWriter(...)
英文:
Some code is so short and simple that ensuring that the test is correct is more complicated than ensuring that the code itself is correct.
Your constructor is such code.
What I would do is either not test it at all, or just call it (using some dummy implementation of net.Conn
) to ensure that it doesn't blow up in smoke when called (therefore called a smoke test).
Later you can test it as part of a bigger test (integration test), where you have a real server to connect to, and which uses your client struct to talk to it.
If you ever find a bug that is due to this constructor, then first add a test that demonstrates the problem, then fix it. Then you will have your test
A test should check that the constructor "works as intended". Checking the value of client.conn
is hardly checking any intended behavior, as the value of an unexported field is not behavior. It just checks HOW the struct and constructor is implemented, not WHAT it implements. Test the what, not the how.
By the way, you could maybe embed a *ReadWriter in your client.
client.buf = bufio.NewReadWriter(...)
答案2
得分: 1
除了@bjarke-ebert所说的之外。
Go语言中没有构造函数,它们只是普通的函数。像测试其他函数一样测试它们。如果一个函数太复杂而无法测试,那么可能有一种方法可以改变设计,使其更易于测试。
此外,根据我的经验,过于关注实现细节的测试(如问题中的测试)很难维护,因为它们需要不断更新。
英文:
In addition to what @bjarke-ebert said.
There are no constructors in Go, they are just normal functions. Test them as you would test any other function. If a function is too complex to test then probably there is a way to change the design to make it more testable.
Also from my experience tests that check internal details of implementation too much (like the test from the question) are very hard to maintain as they constantly need to be updated.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论