不會寫單元測試的程式設計師不是一個合格的滴滴司機

2023-07-03 18:00:31

go內建了一套單元測試機制: 利用 go test測試命令和一套按照約定發方式編寫的測試函數。

在包目錄內,所有以_test.go為字尾名編寫的go檔案不會參與go build的編譯過程.

本文所有的程式碼均放置了帶緩衝區的非同步寫紀錄檔庫

go test 一共三種測試函數:

  • 標準測試函數, 函數以Test為字首,用於測試邏輯行為正確性, go test 會報告測試結果 PASS、FAIL
  • 基準測試函數是以Benchmark為字首的函數,用於衡量函數效能, 拿到平均執行時間
  • 樣例函數, 提供一個編譯器保證正確性的範例檔案

標準測試函數

  • 匯入testing包
  • 以Test開頭,除Test開頭的自定義函數需要首字母大寫
  • 函數引數t *testing.T用於報告測試失敗和附加的紀錄檔資訊
func TestWriteLog(t *testing.T) {

	l := logrus.New()
	l.SetFormatter(&logrus.TextFormatter{
		DisableTimestamp: true,
	})
	l.SetOutput(io.Discard) // Send all logs to nowhere by default
	bh := &BufferedWriterHook{Writer: os.Stdout}
	defer bh.Stop()

	err := bh.Fire(&logrus.Entry{Logger: l, Level: logrus.InfoLevel, Message: "test" + time.Now().Format(time.RFC3339)})
	if err != nil {
		t.Error(t.Name() + " FAIL")
	}
}

基準測試函數

  • 以Benchmark開頭
  • b.N表示迭代次數,不固定,確保至少執行1s
func BenchmarkFire(b *testing.B) {
	l := logrus.New()
	l.SetFormatter(&logrus.TextFormatter{
		DisableTimestamp: true,
	})

	logf, err := os.OpenFile("./log.txt", os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
	if err != nil {
		panic(err)
	}
	defer logf.Close()

	bh := &BufferedWriterHook{Writer: logf}
	defer bh.Stop()

	b.ResetTimer() // 重置計時器,忽略前面的準備時間
	for n := 0; n < b.N; n++ {
		err := bh.Fire(&logrus.Entry{Logger: l, Level: logrus.InfoLevel, Message: "test" + time.Now().Format(time.RFC3339)})
		if err != nil {
			b.Error(b.Name() + " FAIL")
		}
	}
}

go test -bench=. 執行基準測試

以上如果有單元測試,也會執行,若要忽略單元測試,請執行go test -bench=. -count 5 -run=^#

//對https://github.com/zwbdzb/logrus-bufferedWriter-hook執行基準測試
BenchmarkFire-8           940003              1130 ns/op
BenchmarkFire1-8           53912             19678 ns/op

前者是迴圈次數,後者是每次迴圈的平均耗時。

結果顯示 帶非同步緩衝區的logrus寫磁碟能力,是logrus預設同步寫磁碟能力的10+倍。

樣例函數

  • 以Example開頭
  • 需要在程式碼內體現 預期輸出
    go test -run=ExampleHook_default
func ExampleHook_default() {
	l := logrus.New()
	l.SetLevel(logrus.InfoLevel)
	l.SetFormatter(&logrus.TextFormatter{
		DisableTimestamp: true,
	})
	l.SetOutput(io.Discard) // Send all logs to nowhere by default

	ws := &BufferedWriterHook{Writer: os.Stdout}
	defer ws.Stop()
	l.AddHook(ws)

	l.Info("test2")
	l.Warn("test3")
	l.Error("test4")

	// Output:
	// level=info msg=test2
	// level=warning msg=test3
	// level=error msg=test4
}

本文快速記錄了golang單元測試、基準測試、樣例測試的寫法,耗時3h, 有用指數4顆星。

如果你對這個帶緩衝區的非同步寫logrus擴充套件庫https://github.com/zwbdzb/logrus-bufferedWriter-hook 感興趣,歡迎試用 ,期待你的star.