首先,讓我告訴你,我已經看到了與這個問題類似的其他問題,但我認為沒有任何問題真正足夠詳細地回答它(Golang 的單元測驗中如何測驗 net.Conn?以及如何Golang 單元測驗中的一個測驗 net.Conn?)。
我要測驗的是以某種方式回應 TCP 請求的功能。
在最簡單的場景中:
func HandleMessage(c net.Conn) {
s, err := bufio.NewReader(c).ReadString('\n')
s = strings.Trim(s, "\n")
c.Write([]byte(s " whatever"))
}
我將如何對這樣的函式進行單元測驗,理想情況net.Pipe()下不打開實際連接。我一直在嘗試這樣的事情:
func TestHandleMessage(t *testing.T) {
server, client := net.Pipe()
go func(){
server.Write([]byte("test"))
server.Close()
}()
s, err := bufio.NewReader(c).ReadString('\n')
assert.Nil(t, err)
assert.Equal(t, "test whatever", s)
}
但是,我似乎無法理解將HandleMessage(client)( 或HandleMessage(server)?在測驗中實際獲得我想要的回應的位置。我可以讓它阻塞并且根本不會完成,或者它將回傳與我在服務器中撰寫的完全相同的字串。
有人可以幫助我并指出我在哪里犯了錯誤嗎?或者在測驗 TCP 功能時可能指向正確的方向。
uj5u.com熱心網友回復:
該net.Pipe 檔案說:
Pipe 創建一個同步的、記憶體中的、全雙工的網路連接;兩端都實作了 Conn 介面。一端的讀取與另一端的寫入匹配,直接在兩者之間復制資料;沒有內部緩沖。
因此,您附加到net.Conn's (server和client)的標簽是任意的。如果您發現它更容易理解,請隨意使用 something line handleMessageConn, sendMessageConn := net.Pipe()。
下面基本上填寫了您提到的答案中給出的示例。
func TestHandleMessage(t *testing.T) {
server, client := net.Pipe()
// Set deadline so test can detect if HandleMessage does not return
client.SetDeadline(time.Now().Add(time.Second))
// Configure a go routine to act as the server
go func() {
HandleMessage(server)
server.Close()
}()
_, err := client.Write([]byte("test\n"))
if err != nil {
t.Fatalf("failed to write: %s", err)
}
// As the go routine closes the connection ReadAll is a simple way to get the response
in, err := io.ReadAll(client)
if err != nil {
t.Fatalf("failed to read: %s", err)
}
// Using an Assert here will also work (if using a library that provides that functionality)
if string(in) != "test whatever" {
t.Fatalf("expected `test` got `%s`", in)
}
client.Close()
}
你可以扭轉這個局面并將Write/Read放在 go 例程中,但我相信上述方法更容易理解并簡化了避免測驗包的限制:
當其 Test 函式回傳或呼叫任何方法 FailNow、Fatal、Fatalf、SkipNow、Skip 或 Skipf 時,測驗結束。這些方法以及 Parallel 方法只能從運行 Test function 的 goroutine 中呼叫。
注意:如果您不需要net.Conn(就像這個簡單示例中的情況)考慮使用HandleMessage(c io.ReadWriter)(這為用戶提供了更大的靈活性并簡化了測驗)。
uj5u.com熱心網友回復:
阻止并且根本不會完成
好吧,您發布的代碼是如此不完整,以至于我無法知道這些是否是您面臨的真正問題-例如,c在TestHandleMessage. 但是給你帶來懷疑的好處,我會說這段代碼有兩個問題:
首先,您的測驗永遠不會寫入,client因此無法讀取任何內容server。您寫入server并關閉它,但您從未向client. 所以這是第一個問題,但同樣,該代碼無法編譯。
其次,看看這個組合:
c.Write([]byte(s " whatever"))
s, err := bufio.NewReader(c).ReadString('\n')
HandleMessage不寫換行符,但客戶端需要一個。它無限期地掛起,等待永遠不會寫入的換行符。同樣,我不確定您是遇到了這個問題還是第一個問題或兩者兼而有之——因為您的代碼無法編譯。
你必須改變這一行:
c.Write([]byte(s " whatever\n"))
您還必須將初始字串寫入客戶端連接,以便server管道另一端的可以讀取它。
把它們放在一起,拉出任何外部依賴(作證),并修復一些錯誤最終得到:
t.go:
package main
import (
"net"
"fmt"
"bufio"
"strings"
)
func HandleMessage(c net.Conn) {
s, err := bufio.NewReader(c).ReadString('\n')
if err != nil {
panic(fmt.Errorf("HandleMessage could not read: %w", err))
}
s = strings.Trim(s, "\n")
c.Write([]byte(s " whatever\n"))
}
t_test.go:
package main
import(
"net"
"bufio"
"fmt"
"testing"
)
func TestHandleMessage(t *testing.T) {
server, client := net.Pipe()
go func(){
HandleMessage(server)
}()
fmt.Fprintln(client, "test")
s, err := bufio.NewReader(client).ReadString('\n')
if err != nil {
t.Errorf("Error should be nil, got: %s", err.Error())
}
if s != "test whatever\n" {
t.Errorf("Expected result to be 'test whatever\\n', got %s", s)
}
}
% go test t.go t_test.go -v
=== RUN TestHandleMessage
--- PASS: TestHandleMessage (0.00s)
PASS
ok command-line-arguments 0.100s
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/334826.html
