Go語言工程實(shí)踐單元測試基準(zhǔn)測試示例詳解
背景
測試的出現(xiàn)是為了避免項(xiàng)目中出現(xiàn)重大事故
測試是避免事故的最后一道屏障
測試

單元測試的覆蓋率在一定程度上而言,決定了代碼的質(zhì)量
單元測試

通過測試單元的輸出與期望值進(jìn)行校對從而驗(yàn)證代碼的正確性,從而保證新舊代碼的互不影響與程序的正常運(yùn)行。
進(jìn)而單元測試較于編譯更易于在較短的周期內(nèi)發(fā)現(xiàn)和定位代碼中的錯(cuò)誤使損失最小化從而提升效率。所以寫單元測試是很有必要的。
Golang單元測試對文件名和方法名,參數(shù)都有很嚴(yán)格的要求。
- 文件名必須以
xx_test.go命名 - 方法必須是
Test[^a-z]開頭 - 方法參數(shù)必須
t *testing.T - 初始化邏輯放到TestMain中
- 使用
go test執(zhí)行單元測試
演示
通過第三方包assert演示單元測試
判斷函數(shù)測試值與期望值是否一致
import(
"github.com/stretchr/testify/assert"
"testing"
)
func TestHelloTom(t *testing.T) {
output := HelloTom()
expectOutput := "Tom"
assert.Equal(t, expectOutput, output)
}
func HelloTom() string {
return "Tom"
}
覆蓋率
覆蓋率出現(xiàn)的目的:
- 衡量代碼是否經(jīng)過了足夠的測試
- 評價(jià)項(xiàng)目的測試水準(zhǔn)
- 評估項(xiàng)目是否達(dá)到了高水準(zhǔn)測試等級
通過go test命令測試函數(shù)的覆蓋率
// judgment.go
func JudgePassLine(score int16) bool {
if score >= 60 {
return true
}
else {
return false
}
}
// judgment_test.go
func TestJudgePassLineTrue(t *testing.T) {
isPass := JudgeePassLine(70)
assert.Equal(t, true, isPass)
}
func TestJudgePassLineFalse(t *testing.T) {
isPass := JudgeePassLine(50)
assert.Equal(t, false, isPass)
}
/*
通過go test 命令測試覆蓋率
go test judgment_test.go judgment.go --cover
*/
一般覆蓋率:50%~60%,較高覆蓋率:80%+
測試分支相互獨(dú)立、全面覆蓋
對于上述案例代碼而言
應(yīng)出現(xiàn)成績大于等于60 和小于60的測試用力
測試單元粒度足夠小,函數(shù)單一職責(zé)
依賴

- 冪等:重復(fù)運(yùn)行同一個(gè)case,結(jié)果與之前一致
- 穩(wěn)定:指單元測試相互隔離,可以獨(dú)立運(yùn)行
文件處理
當(dāng)測試文件被修改后,可能會(huì)導(dǎo)致測試失敗或錯(cuò)誤率增高
從而出現(xiàn)了Mock函數(shù)
func ReadFirstLine() string {
open, err := os.Open("log") // 打開一個(gè)文件
defer open.Close()
if err != nil {
return ""
}
scanner := bufio.NewScanner(open) // 對每行進(jìn)行遍歷
for scanner.Scan() {
return scanner.Text()
}
return ""
}
func ProcessFirstLine() string {
line := ReadFirstLine()
destLine := strings.ReplaceAll(line, "11", "00") // 替換11為00
return destLine
}
func TestProcessFirstLine(t *testing.T) { // 執(zhí)行單元測試
firstLine := ProcessFirstLine()
assert.Equal(t, "line00", firstLine)
}
Mock
monkey: github.com/bouk/monkey 這是一個(gè)開源的mock測試庫,可以對method或者實(shí)例的方法進(jìn)行mock
Monkey Patch的作用域在Runtime, 運(yùn)行時(shí)通過Go的unsafe包能夠?qū)?nèi)存中函數(shù)的地址替換為運(yùn)行時(shí)函數(shù)的地址,將待打樁函數(shù)或方法的實(shí)現(xiàn)跳轉(zhuǎn)。
Mock函數(shù)不僅可以為一個(gè)函數(shù)打樁 也可以為一個(gè)方法打樁
// 用函數(shù)A去替換函數(shù)B,B就是原函數(shù),A就是打樁函數(shù)
func Patch(target, replacement interface{}) *PatchGuard {
// target就是原函數(shù),replacement就是打樁函數(shù)
t := reflect.ValueOf(target)
r := reflect.ValueOf(replacement)
patchValue(t, r)
return &PatchGuard{t, r}
}
func Unpatch(target interface{}) bool {
// 保證了在測試結(jié)束之后需要把這個(gè)包卸載掉
return unpatchValue(reflect.ValueOf(target))
}
func TestProcessFirstLineWithMock(t *testing.T) {
monkey.Patch(ReadFirstLine, func() string {
return "line110"
})
defer monkey.Unpatch(ReadFirstLine)
line := ProcessFirstLine()
assert.Equal(t, "line000", line)
}
// 通過patch對ReadFirstLine進(jìn)行打樁mock,默認(rèn)返回line110,通過defer卸載mock
// 這樣整個(gè)測試函數(shù)就擺脫了本地文件的束縛和依賴
基準(zhǔn)測試
基準(zhǔn)測試是指測試一段程序的性能及耗費(fèi)CPU的程度;
在實(shí)際的項(xiàng)目開發(fā)中,經(jīng)常會(huì)遇到代碼性能瓶頸,為了定位問題,經(jīng)常要對代碼做性能分;
這時(shí)就用到了基準(zhǔn)測試,其使用方法與單元測試類似。
- 優(yōu)化代碼,需要對當(dāng)前代碼分析
- 內(nèi)置的測試框架提供了基準(zhǔn)測試的能力
小結(jié)
對于今日課程而言,我將其劃分成測試的重要性與分類。 當(dāng)前課程余下部分為項(xiàng)目實(shí)戰(zhàn),該部分內(nèi)容選擇了放置于項(xiàng)目筆記。 如果筆記中有錯(cuò)誤的地方也希望掘友們可以及時(shí)的提出糾正,更多關(guān)于Go語言單元測試基準(zhǔn)測的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Go語言優(yōu)雅實(shí)現(xiàn)單例模式的多種方式
單例模式(Singleton Pattern)是一種設(shè)計(jì)模式,旨在保證一個(gè)類只有一個(gè)實(shí)例,并且提供全局訪問點(diǎn),單例模式通常用于需要限制某個(gè)對象的實(shí)例數(shù)量為一個(gè)的場景,本文給大家介紹了Go語言實(shí)現(xiàn)單例模式的多種方式,需要的朋友可以參考下2025-02-02

