返回首頁
當前位置: 主頁 > 網絡編程 > Asp實例教程 >

如何得知golang代碼覆蓋率

時間:2017-09-13 20:58來源:知行網www.aotfjk.live 編輯:麥田守望者

以前寫程序時,很少關注單元測試。 即便寫,也是草草了事。沒有很認真的寫過,更別談統計代碼覆蓋率了。出現這種情況固然是不對的, 但也跟市面上缺乏準確有效的代碼覆蓋率統計工具有一絲關系吧。

golang的出現對這種局面有了一些改變。 golang定位于工程化語言,所以其也自帶了一部分有用的輔助工具。而cover tool就是其中一個很有用的代碼覆蓋率統計工具。

golang的cover工具基本原理和其它工具類似,都是在原始代碼中尋找分支,然后在每個分支"種下"錨點。 等所有的case都跑完后,通過統計執行錨點的數量來計算覆蓋率。

假如我們有如下的代碼:
package size

func Size(a int) string {
switch {
case a < 0:
return "negative"
case a == 0:
return "zero"
case a < 10:
return "small"
case a < 100:
return "big"
case a < 1000:
return "huge"
}
return "enormous"
}


golang在分析完分支之后,種下錨點:
func Size(a int) string {
GoCover.Count[0] = 1
switch {
case a < 0:
GoCover.Count[2] = 1
return "negative"
case a == 0:
GoCover.Count[3] = 1
return "zero"
case a < 10:
GoCover.Count[4] = 1
return "small"
case a < 100:
GoCover.Count[5] = 1
return "big"
case a < 1000:
GoCover.Count[6] = 1
return "huge"
}
GoCover.Count[1] = 1
return "enormous"
}


這樣當所有case運行完后,通過計算GoCover的Count數量來計算覆蓋率。以上這些工作都是golang自己完成,而不需要用戶參與。

我們用上一篇出現的mongo unit test code來做demo,看看cover tool如何使用。 業務代碼如下:
package main

import (
"fmt"
"log"
"time"

mgo "gopkg.in/mgo.v2"
)

type dpi struct {
Area string `json:"area`
Count int `json:"count"`
}

func GetMongo() *mgo.Session {
login := &mgo.DialInfo{
Addrs: []string{"10.50.1.60:1301"},
Timeout: 3600 * time.Second,
Database: "DPI_URL",
}
log.Printf("Connectting mongodb, host:[%s] db:[%s]\n", login.Addrs, login.Database)
mgoSession, err := mgo.DialWithInfo(login)
if err != nil {
fmt.Println(err.Error())
}

if err := mgoSession.Ping(); err == nil {
log.Printf("MONGO CONNECT SUCCESS! [%s]\n", mgoSession.LiveServers())
} else {
log.Printf("MONGO CONNECT FAILED!! [10.50.1.60:1301] Error Info [%s]\n", err.Error())
}

session := mgoSession.Clone()
if session == nil {
fmt.Println("MONGODB SESSION IS NIL!!")
return nil
}

return session
}

func main() {
session := GetMongo()

c := session.DB("DPI_URL").C("DATA_COUNT")

ds := getDPI(c)

for _, d := range ds {
log.Println(d)
}
}

func getDPI(c *mgo.Collection) []dpi {
var ds []dpi
err := c.Find(nil).All(&ds)
if err != nil {
log.Println(err.Error())
}

return ds
}


Unit test 代碼如下:
package main

import (
"log"
"testing"

"gopkg.in/check.v1"
mgo "gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/dbtest"
)

var col *mgo.Collection
var server dbtest.DBServer
var session *mgo.Session

var ds = []interface{}{
dpi{Area: "a1", Count: 100},
dpi{Area: "a2", Count: 200},
dpi{Area: "a3", Count: 300},
}

func init() {
server.SetPath("/tmp")
session = server.Session()

if session == nil {
log.Panicln("Can not get mongo session")
}

col = session.DB("tdb").C("tc")
col.RemoveAll(nil)

}

type S struct{}

var _ = check.Suite(&S{})

func TestAll(t *testing.T) {
check.TestingT(t)
}

func (s *S) TestGetDpi(c *check.C) {
defer func() {
session.Close()
server.Stop()
}()

col.Insert(ds...)

dv := getDPI(col)

if len(dv) != 3 {
c.Error("dv size is error")
}

if dv[0].Area != "a1" || dv[1].Area != "a2" || dv[2].Area != "a3" {
c.Error("dv is error")
}

log.Println("OK")
}


現在來看看代碼覆蓋率:
[email protected]:/go/src/mongo# go test -cover
2017/04/26 07:02:24 OK
OK: 1 passed
PASS
coverage: 17.4% of statements
ok mongo 0.708s
17.4%.... 很低的一個覆蓋率。 如何提升覆蓋率呢? 這個問題golang也想到了,所以golang會給我們一些更為有用的信息。


下面讓golang來收集更多的覆蓋信息:
go test -coverprofile=coverage.out
2017/04/26 07:00:15 OK
OK: 1 passed
PASS
coverage: 17.4% of statements
ok mongo 0.748s


執行完之后,沒有輸出更多有用的信息。 那會不會保存在coverage.out里面了呢?
[email protected]:/go/src/mongo# more coverage.out
mode: set
mongo/main.go:16.30,24.16 4 0
mongo/main.go:28.2,28.42 1 0
mongo/main.go:34.2,35.20 2 0
mongo/main.go:40.2,40.16 1 0
mongo/main.go:24.16,26.3 1 0
mongo/main.go:28.42,30.3 1 0
mongo/main.go:30.3,32.3 1 0
mongo/main.go:35.20,38.3 2 0
mongo/main.go:43.13,50.23 4 0
mongo/main.go:50.23,52.3 1 0
mongo/main.go:55.38,58.16 3 1
mongo/main.go:62.2,62.11 1 1
mongo/main.go:58.16,60.3 1 0


好吧,完全看不懂。 換種格式來看看:
go tool cover -func=coverage.out
mongo/main.go:16: GetMongo 0.0%
mongo/main.go:43: main 0.0%
mongo/main.go:55: getDPI 80.0%
total: (statements) 17.4%

如何得知golang代碼覆蓋率
如何得知golang代碼覆蓋率
 


如此一來,我們就知道了。 只有getDPI函數覆蓋了80%,其它兩個函數丁點沒有覆蓋,因此加權之后就是17.4%了。getDPI沒有覆蓋的代碼是哪些呢? golang同樣也可以告訴你:
go tool cover -html=coverage.out
HTML output written to /tmp/cover819344406/coverage.html


可以看到在getDPI函數中,log.Println(err.Error())被標紅處理了,也就是說這行沒有被覆蓋到。 同理上面所有標紅的代碼都沒有被覆蓋到。

寫到這里,基本上golang cover工具就夠我們使用了。 但我們探索的腳本還不想停下來,看看cover還有哪些潛力。因為golang的cover工具是基于源碼進行統計的,那么它能不能統計遞歸次數呢?也就是看看每個函數的heat maps。

golang使用-covermode來接受用戶的統計指令:
•set: 統計每個函數是否都執行了
•count:統計每個函數執行了多少次
•atomic:和count作用類似,但是用在并發場景中統計執行次數。

默認情況下,我們使用的都是set。 下面我們用fmt來演示一下使用count的結果:
go test -covermode=count -coverprofile=count.out fmt
ok fmt 0.056s coverage: 91.7% of statements
不虧是golang官方包,91.7的代碼覆蓋率。。。

go tool cover -func=count.out
fmt/format.go: init 100.0%
fmt/format.go: clearflags 100.0%
fmt/format.go: init 100.0%
fmt/format.go: computePadding 84.6%
fmt/format.go: writePadding 100.0%
fmt/format.go: pad 100.0%
...
fmt/scan.go: advance 96.2%
fmt/scan.go: doScanf 96.8%
total: (statements) 91.7%


用一種直觀的方式表示一下:

go tool cover -html=count.out

越綠的代碼就表示調用次數越高,把鼠標移到上面就可以看到每行代碼的調用次數。

以上就是我對golang test cover工具的一些使用心得,希望能對你有所幫助。 如果你有什么想交流的,不要吝嗇您的留言。

------分隔線----------------------------
標簽(Tag):Golang golang代碼覆蓋率
------分隔線----------------------------
推薦內容
猜你感興趣
湖南刘雪龙黑彩