go-單元測試

單元測試

先看一個需求
在咱們工做中,咱們會遇到這樣的狀況,就是去確認一個函數,或者一個模塊的結果是否正確.
傳統的方法
15.2.1 傳統的方式來進行測試
在 main 函數中,調用 addUpper 函數,看看實際輸出的結果是否和預期的結果一致,若是一致,
則說明函數正確,不然函數有錯誤,而後修改錯誤json

傳統方法的缺點分析

1) 不方便, 咱們須要在 main 函數中去調用,這樣就須要去修改 main 函數,若是如今項目正在運
行,就可能去中止項目。
2) 不利於管理,由於當咱們測試多個函數或者多個模塊時,都須要寫在 main 函數,不利於咱們管
理和清晰咱們思路
3) 引出單元測試。-> testing 測試框架 能夠很好解決問題。併發

單元測試-基本介紹

Go 語言中自帶有一個輕量級的測試框架 testing 和自帶的 go test 命令來實現單元測試和性能測試,
testing 框架和其餘語言中的測試框架相似,能夠基於這個框架寫針對相應函數的測試用例,也能夠基
於該框架寫相應的壓力測試用例。經過單元測試,能夠解決以下問題
1) 確保 每一個函數是可運行,而且運行結果是正確的
2) 確保寫出來的代碼 性能是好的,
3) 單元測試能及時的發現程序設計或實現的 邏輯錯誤,使問題及早暴露,便於問題的定位解決,
而 性能測試的重點在於發現程序設計上的一些問題,讓程序可以在高併發的狀況下還能保持穩定框架

 單元測試-快速入門

使用 Go 的單元測試,對 addUpper 和 sub 函數進行測試。
特別說明: 測試時,可能須要暫時退出 360。(由於 360 可能會認爲生成的測試用例程序是木馬)函數

單元測試快速入門總結
1) 測試用例文件名必須以 _test.go 結尾。 好比 cal_test.go , cal 不是固定的。
2) 測試用例函數必須以 Test 開頭,通常來講就是 Test+被測試的函數名,好比 TestAddUpper
3) TestAddUpper(t tesing.T) 的形參類型必須是 testing.T 【看一下手冊】
4) 一個測試用例文件中,能夠有多個測試用例函數,好比 TestAddUpper、TestSub
5) 運行測試用例指令高併發

(1) cmd>go test [若是運行正確,無日誌,錯誤時,會輸出日誌]性能

(2) cmd>go test -v [運行正確或是錯誤,都輸出日誌]
6) 當出現錯誤時,可使用 t.Fatalf 來格式化輸出錯誤信息,並退出程序
7) t.Logf 方法能夠輸出相應的日誌
8) 測試用例函數,並無放在 main 函數中,也執行了,這就是測試用例的方便之處.
9) PASS 表示測試用例運行成功,FAIL 表示測試用例運行失敗
10) 測試單個文件,必定要帶上被測試的原文件
go test -v cal_test.go cal.go
11) 測試單個方法
go test -v -test.run TestAddUpper單元測試

main包中:main.go測試

package main
import (
    _ "fmt"
)

//一個被測試函數
func addUpper(n int)  int {
    res := 0
    for i := 1; i <= n - 1; i++ {
        res += i
    }
    return res
}

func addUpper2(n int)  int {
    res := 0
    for i := 1; i <= n - 1; i++ {
        res += i
    }
    return res
}

func main() {

    //傳統的測試方法,就是在main函數中使用看看結果是否正確
    // res := addUpper(10) // 1.+ 10 = 55
    // if res != 55 {
    //  fmt.Printf("addUpper錯誤 返回值=%v 指望值=%v\n", res, 55)
    // } else {
    //  fmt.Printf("addUpper正確 返回值=%v 指望值=%v\n", res, 55)
    // }
}

text包中:cal_test.gothis

package cal
import (
    "fmt"
    "testing" //引入go 的testing框架包
)

//編寫要給測試用例,去測試addUpper是否正確
func TestAddUpper(t *testing.T) {

    //調用
    res := addUpper(10)
    if res != 55 {
        //fmt.Printf("AddUpper(10) 執行錯誤,指望值=%v 實際值=%v\n", 55, res)
        t.Fatalf("AddUpper(10) 執行錯誤,指望值=%v 實際值=%v\n", 55, res)
    }

    //若是正確,輸出日誌
    t.Logf("AddUpper(10) 執行正確...")

}

func TestHello(t *testing.T) {

    fmt.Println("TestHello被調用..")

}

text包中:sub_test.go設計

package cal
import (
    _ "fmt"
    "testing" //引入go 的testing框架包
)

//編寫要給測試用例,去測試addUpper是否正確
func TestGetSub(t *testing.T) {

    //調用
    res := getSub(10, 3)
    if res != 7 {
        //fmt.Printf("AddUpper(10) 執行錯誤,指望值=%v 實際值=%v\n", 55, res)
        t.Fatalf("getSub(10, 3) 執行錯誤,指望值=%v 實際值=%v\n", 7, res)
    }

    //若是正確,輸出日誌
    t.Logf("getSub(10, 3) 執行正確!!!!...")

}

text包中:cal.go

package cal

//一個被測試函數
func addUpper(n int)  int {
    res := 0
    for i := 1; i <= n - 1; i++ {
        res += i
    }
    return res
}

//求兩個數的查
func getSub(n1 int, n2 int) int {
    return n1 - n2
}

單元測試-綜合案例

如下兩個文件處在一個包中:
monster.go:

package monster
import (
    "encoding/json"
    "io/ioutil"
    "fmt"
)

type Monster struct {
    Name string
    Age int
    Skill string
} 

//給Monster綁定方法Store, 能夠將一個Monster變量(對象),序列化後保存到文件中

func (this *Monster) Store() bool {

    //先序列化
    data, err := json.Marshal(this)
    if err != nil {
        fmt.Println("marshal err =", err)
        return false
    } 

    //保存到文件
    filePath := "d:/monster.ser"
    err = ioutil.WriteFile(filePath, data, 0666)
    if err != nil {
        fmt.Println("write file err =", err)
        return false
    }
    return true
}


//給Monster綁定方法ReStore, 能夠將一個序列化的Monster,從文件中讀取,
//並反序列化爲Monster對象,檢查反序列化,名字正確
func (this *Monster) ReStore() bool {

    //1. 先從文件中,讀取序列化的字符串
    filePath := "d:/monster.ser"
    data, err := ioutil.ReadFile(filePath)
    if err != nil {
        fmt.Println("ReadFile err =", err)
        return false
    }

    //2.使用讀取到data []byte ,對反序列化
    err = json.Unmarshal(data, this)
    if err != nil {
        fmt.Println("UnMarshal err =", err)
        return false
    }
    return true
}

monster_test.go:

package monster

import (
    "testing"
)

//測試用例,測試 Store 方法
func TestStore(t *testing.T) {

    //先建立一個Monster 實例
    monster := &Monster{
        Name : "紅孩兒",
        Age :10,
        Skill : "吐火.",
    }
    res := monster.Store()
    if !res {
        t.Fatalf("monster.Store() 錯誤,但願爲=%v 實際爲=%v", true, res)
    }
    t.Logf("monster.Store() 測試成功!")
}

func TestReStore(t *testing.T) {

    //測試數據是不少,測試不少次,才肯定函數,模塊..
    
    //先建立一個 Monster 實例 , 不須要指定字段的值
    var monster = &Monster{}
    res := monster.ReStore() 
    if !res {
        t.Fatalf("monster.ReStore() 錯誤,但願爲=%v 實際爲=%v", true, res)
    }

    //進一步判斷
    if monster.Name != "紅孩兒" {
        t.Fatalf("monster.ReStore() 錯誤,但願爲=%v 實際爲=%v", "紅孩兒", monster.Name)
    }

    t.Logf("monster.ReStore() 測試成功!") 
}
相關文章
相關標籤/搜索