如何测试依赖net.Conn的代码而不创建实际的网络连接? [英] How can you test code that relies on net.Conn without creating an actual network connection?
问题描述
如果我的代码可以和 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 $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ 在我做一些小例子之前,我们需要解决一个重要的问题: 我们不测试净包装。我们认为,软件包没有任何错误,并且确实如此,文档说明了什么。这意味着我们不关心Go团队如何实施 您没有发布任何代码片段,所以我只给你一个简单的例子。我想你有一个方法或函数,你使用的是网络包。 你可以测试你需要重构你的函数,所以它只是使用net.Conn接口。为此,必须将 新函数可能如下所示: 第2步:实现网络.Conn接口 测试您需要实现net.Conn接口: 包括小型支票的完整实施: S第3步:测试 测试时,我们不关心 所以在测试时,你应该总是认为关于你想测试的功能。我认为这是真正最难以抽象出真正想写的功能的部分。在简单的单元测试中,您绝对不应该测试标准库的功能。希望这些例子可以帮助你重新找回正确的轨道。 If I have code that works with a 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, (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 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. 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 The new function could look something like that: Step 2: Implement the net.Conn interface For testing you need to implement the net.Conn interface: Complete implementation including a small type check:
https://play.golang.org/p/taAmI61vVz Step 3: Testing When testing, we don't care about the 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屋!
$ b
SetReadDeadline
和 SetWriteDeadline
。我们只测试程序中的用法。第1步:重构代码
func myConn(...)error {
//你的代码在这里
c,err:= net.Dial(tcp,12.34.56.78:80)
c.setDeadline(t)
//更多代码在这里
}
net.Dial()
调用移出函数。请记住,我们不想测试net.Dial函数。
func myConn(c,net.Conn,...)错误{
//您的代码在这里
c.setDeadline(t)
//在此更多代码
}
<$ 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
Dial()
方法,我们只是创建一个指向我们的测试类型的指针,它实现了net.Conn接口并将其放入你的函数中。然后,如果deadline参数设置正确,我们会查看我们的测试用例。
func TestMyConn(t * testing.T){
myconnTester =& connTester {}
err:= myConn(myconnTester,...)
...
if myconntester.deadline!= expectedDeadline {
/ /测试失败
}
}
net.Conn
, how can I write tests for it without actually creating a network connection to localhost?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")}
}
SetReadDeadline
and SetWriteDeadline
. We test only the usage in our programm. func myConn(...) error {
// You code is here
c, err := net.Dial("tcp", "12.34.56.78:80")
c.setDeadline(t)
// More code here
}
net.Dial()
call has to be moved outside of the function. Remember that we don't want to test the net.Dial function.func myConn(c, net.Conn, ...) error {
// You code is here
c.setDeadline(t)
// More code here
}
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
}
...
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
}
}