如果我有与一起使用的代码net.Conn,如何在不实际创建与localhost的网络连接的情况下为其编写测试?
net.Conn
我在网上没有看到任何解决方案。人们似乎忽略了它(没有测试),编写了不能并行运行的测试(即使用实际的网络连接,使用了端口),或者使用了io.Pipe。
然而,net.Conn限定SetReadDeadline,SetWriteDeadline; 而io.Pipe没有。net.Pipe 也 没有,尽管从表面上声称实现了该接口,但它只是通过以下方式实现:
SetReadDeadline
SetWriteDeadline
func (p *pipe) SetDeadline(t time.Time) error { return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (p *pipe) SetReadDeadline(t time.Time) error { return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (p *pipe) SetWriteDeadline(t time.Time) error { return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} }
(请参阅:https : //golang.org/src/net/pipe.go)
那么…还有其他方法可以做到吗?
我将接受任何显示如何在测试截止时间(不是实际的网络套接字)中使用流的答案。
理想情况下,此cloudflare博客文章涵盖了使用截止日期的动机,以及为什么在每个连接的goroutine中永远阻塞不是可接受的解决方案;但是不管那种说法如何,尤其是在这种情况下,我正在寻找一种 针对测试 的解决方案,我们故意想要处理连接不良的情况下等)
(注意。这似乎是Go中Simulatetcp连接的复制品,但请注意,该问题中提出的所有解决方案均未实现Deadline函数,这正是我要问的此处测试方法)
您的问题很开放,因此不可能给您“正确答案”。但是我想我理解您遇到的困难。这个答案也是开放的,但是它应该使您回到正确的轨道上。
几天前,我写了一篇简短的文章,其中显示了您必须使用的原理。
在我举一些小例子说明您的测试如何工作之前,我们需要修正一个重要点:
我们 不测试网络包装 。我们假设 该文件包没有错误 ,但确实如此。这意味着 我们不在乎Go团队如何实现 SetReadDeadline和 实现SetWriteDeadline。我们仅在程序中测试用法。
步骤1:重构代码
您没有发布任何代码段,因此我仅举一个简单的示例。我猜你有一个方法或函数,正在使用net包。
func myConn(...) error { // You code is here c, err := net.Dial("tcp", "12.34.56.78:80") c.setDeadline(t) // More code here }
能够测试您需要重构功能的功能,因此它仅使用net.Conn接口。为此,必须将net.Dial()调用移到函数之外。请记住,我们不想测试net.Dial函数。
net.Dial()
新功能可能如下所示:
func myConn(c, net.Conn, ...) error { // You code is here c.setDeadline(t) // More code here }
步骤2:实现net.Conn接口
为了进行测试,您需要实现net.Conn接口:
type connTester struct { deadline time.Time } func (c *connTester) Read(b []byte) (n int, err error) { return 0, nil } ... func (c *connTester) SetDeadline(t time.Time) error { c.deadline = t return nil } ...
完整的实现,包括小的类型检查:https : //play.golang.org/p/taAmI61vVz
步骤3:测试
在测试时,我们并不关心Dial()方法,我们只是创建一个指向我们的测试类型的指针,该指针实现了net.Conn接口并将其放入您的函数中。然后,如果最后期限参数设置正确,我们将查看测试用例。
Dial()
func TestMyConn(t *testing.T){ myconnTester = &connTester{} err := myConn(myconnTester,...) ... if myconntester.deadline != expectedDeadline{ //Test fails } }
因此,在测试时,您应该始终考虑要测试的功能。我认为对您真正想要编写的功能进行抽象是最困难的部分。在简单的单元测试中,您永远不要测试标准库的功能。希望这个例子可以帮助您重新走上正轨。