如何得知golang程式碼涵蓋範圍

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

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

golang的出現對這種局面有了一些改變。 golang定位於工程化語言,所以其也內建了一部分有用的協助工具輔助。而cover tool就是其中一個很有用的程式碼涵蓋範圍統計工具。

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

假如我們有如下的代碼:

package sizefunc 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 mainimport (      "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 mainimport (      "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.Sessionvar 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")}

現在來看看程式碼涵蓋範圍:

root@d206835c4fc7:/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裡面了呢?

root@d206835c4fc7:/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%  

如此一來,我們就知道了。 只有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工具的一些使用心得,希望能對你有所協助。 如果你有什麼想交流的,不要吝嗇您的留言。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.