如何测试依赖net.Conn的代码而不创建实际的网络连接? [英] How can you test code that relies on net.Conn without creating an actual network connection?

查看:190
本文介绍了如何测试依赖net.Conn的代码而不创建实际的网络连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我的代码可以和 net.Conn 一起工作,那么如何在不为本地主机创建网络连接的情况下编写测试?



我没有看到这方面的解决方案。人们似乎忽略它(没有测试),编写无法并行运行的测试(即使用实际的网络连接,它使用了端口),或者使用io.Pipe。

但是, net.Conn 定义 SetReadDeadline SetWriteDeadline ;而io.Pipe没有。 net.Pipe 不会,尽管表面声称实现了接口,它只是简单的实现:

  func(p * pipe)SetDeadline(t time.Time)error {
return& OpError {Op:set,Net:pipe,source:nil,Addr:nil,Err:errors.New 不支持截止日期)}
}

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 blogpost 涵盖了使用截止日期的动机,以及为什么在每个连接中永远阻塞在一个goroutine中不是一个可接受的解决方案;但无论如何,特别是在这种情况下,我正在寻找一个解决方案 for测试,我们故意要处理边连接不好的情况,等等。)



(注意,这可能看起来像是在Go上模拟tcp连接,但请注意,在该问题中提出的所有解决方案不要实现截止日期函数,这正是我所要求的关于如何测试的)

你的问题非常开放,所以不可能给你正确的答案。但我想我明白你卡在哪里。这个答案也是开放的,但它会让你回到正确的轨道。



几天前,我写了一个 $ b $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $
$ b

在我做一些小例子之前,我们需要解决一个重要的问题:

我们不测试净包装。我们认为,软件包没有任何错误,并且确实如此,文档说明了什么。这意味着我们不关心Go团队如何实施 SetReadDeadline SetWriteDeadline 。我们只测试程序中的用法。第1步:重构代码



您没有发布任何代码片段,所以我只给你一个简单的例子。我想你有一个方法或函数,你使用的是网络包。

  func myConn(...)error { 
//你的代码在这里
c,err:= net.Dial(tcp,12.34.56.78:80)
c.setDeadline(t)
//更多代码在这里
}

你可以测试你需要重构你的函数,所以它只是使用net.Conn接口。为此,必须将 net.Dial()调用移出函数。请记住,我们不想测试net.Dial函数。

新函数可能如下所示:

  func myConn(c,net.Conn,...)错误{
//您的代码在这里
c.setDeadline(t)
//在此更多代码
}

第2步:实现网络.Conn接口

测试您需要实现net.Conn接口:

<$ p $ (c * connTester)读取(b []字节)(n int,p)类型connTester struct {
截止时间.Time
}

func err错误){
return 0,nil
}

...

func(c * connTester)SetDeadline(t time.Time)error {
c.deadline = t
return nil
}

...

包括小型支票的完整实施:
https: //play.golang.org/p/taAmI61vVz



S第3步:测试



测试时,我们不关心 Dial()方法,我们只是创建一个指向我们的测试类型的指针,它实现了net.Conn接口并将其放入你的函数中。然后,如果deadline参数设置正确,我们会查看我们的测试用例。

  func TestMyConn(t * testing.T){ 
myconnTester =& connTester {}
err:= myConn(myconnTester,...)
...
if myconntester.deadline!= expectedDeadline {
/ /测试失败
}
}

所以在测试时,你应该总是认为关于你想测试的功能。我认为这是真正最难以抽象出真正想写的功能的部分。在简单的单元测试中,您绝对不应该测试标准库的功能。希望这些例子可以帮助你重新找回正确的轨道。


If I have code that works with a net.Conn, how can I write tests for it without actually creating a network connection to localhost?

I've seen no solutions to this online; people seem to either ignore it (no tests), write tests that cannot run in parallel (ie. use an actual network connection, which uses up ports), or use io.Pipe.

However, net.Conn defines SetReadDeadline, SetWriteDeadline; and io.Pipe doesn't. net.Pipe also doesnt, despite superficially claiming to implement the interface, it's simply implemented with:

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")}
}

(see: https://golang.org/src/net/pipe.go)

So... is there some other way of doing this?

I'll accept any answer that shows how to use a stream in a test with a working deadline that is not an actual network socket.

(Idly, this cloudflare blogpost covers the motivation for using deadlines, and why blocking forever in a goroutine per connection is not an acceptable solution; but regardless of that argument, particularly in this case I'm looking for a solution for tests where we deliberately want to handle edge cases where a bad connection hangs, etc.)

(NB. this may seem like a duplicate of Simulate a tcp connection in Go, but notice that all the solutions proposed in that question do not implement the Deadline functions, which is specifically what I'm asking about how to test here)

解决方案

Your question is very open, so it is not possible to give you "the correct answer". But I think I understand the point where you stuck. This answer is also open, but it should bring you back on the right track.

A few days ago I wrote a short article, which shows the principle which you have to use.

Before I make some small examples how you such tests work, we need to fix one important point:

We do not test the net package. We asume, that the package has no bug and does, what the documentation says. That means we do not care how the Go team has implementet SetReadDeadline and SetWriteDeadline. We test only the usage in our programm.

Step 1: Refactoring your code

You did not post any code snippets, so I give you just a simple example. I guess you have a method or function, where you are using the net package.

func myConn(...) error {
  // You code is here
  c, err := net.Dial("tcp", "12.34.56.78:80")
  c.setDeadline(t)
  // More code here
}

That you are able to to test you need to refactor your function, so it is just using the net.Conn interface. To do this, the net.Dial() call has to be moved outside of the function. Remember that we don't want to test the net.Dial function.

The new function could look something like that:

func myConn(c, net.Conn, ...) error {
  // You code is here
  c.setDeadline(t)
  // More code here
}

Step 2: Implement the net.Conn interface

For testing you need to implement the net.Conn interface:

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
}

...

Complete implementation including a small type check: https://play.golang.org/p/taAmI61vVz

Step 3: Testing

When testing, we don't care about the Dial() Method, we just create a pointer to our testtype, which implements the net.Conn interface and put it into your function. Afterwards we look inside our test cases, if the deadline parameter is set correctly.

func TestMyConn(t *testing.T){
  myconnTester = &connTester{}
  err := myConn(myconnTester,...)
  ...
  if myconntester.deadline != expectedDeadline{
  //Test fails
  }
}

So when testing, you should always think about, what feature you want to test. I think it is the really most difficult part to abstract the functionality you really want to write. Inside of simple unit tests you should never test functionalities of the standard library. Hope this examples can help you to bring you back on the right track.

这篇关于如何测试依赖net.Conn的代码而不创建实际的网络连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆