<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          「GoCN酷Go推薦」golang 單元測試最佳實(shí)踐

          共 4418字,需瀏覽 9分鐘

           ·

          2021-09-27 10:28

          為什么要進(jìn)行單元測試?

          在沒工作之前,說實(shí)話沒怎么寫過單元測試,很多情況下就是一邊寫代碼,一邊運(yùn)行,用 fmt.Println() 打印變量,再稍微復(fù)雜一點(diǎn)的也許會用 dlv 去 debug 代碼,找出問題。

          但是在做公司做大型項(xiàng)目時就會發(fā)現(xiàn),你根本就沒辦法把項(xiàng)目跑起來,這個時候你只能通過寫單元測試去看自己的邏輯對不對。

          當(dāng)然仍舊會出現(xiàn)一個問題,當(dāng)你的功能中又調(diào)用了其他的接口,但這個接口在你當(dāng)前的環(huán)境中是沒辦法正常調(diào)用的,比如數(shù)據(jù)庫連接,文件 I/O。網(wǎng)絡(luò)I/O 等。這個時候就需要一個 好用的 mock 庫了,簡單來說就是用 mock 對象模擬依賴項(xiàng)的行為,這里我推薦使用 gomonkey。

          從另一個角度講,為什么需要單元測試呢,因?yàn)槲覀円话沩?xiàng)目都有覆蓋率的要求,寫單測當(dāng)然是也是為了提高代碼覆蓋率咯,不然代碼都無法提交到 gitlab 上。

          gomonkey 入門

          安裝 gomonkey

          go get github.com/agiledragon/gomonkey

          gomonkey 常見用法

          • mock 一個函數(shù)

          • mock 一個成員方法

          • 其他用法可參考官方文檔

          業(yè)務(wù)代碼如下:

          package mock

          import (
           "encoding/json"
           "io/ioutil"
           "net/http"
          )

          type Request struct {
           Url string
          }

          type Response struct {
           Result string
          }

          func exec(args []byte) (res *Response, err error) {
           var w Request
           if err = json.Unmarshal(args, &w); err != nil {
            return nil, err
           }
           if res, err = w.DoAction(w.Url); err != nil {
            return nil, err
           }
           return
          }

          func (r *Request) DoAction(action string) (resp *Response, err error) {
           var (
            res *http.Response
            b   []byte
           )
           if res, err = http.Get(action); err != nil {
            return nil, err
           }
           if b, err = ioutil.ReadAll(res.Body); err != nil {
            return nil, err
           }
           return &Response{Result: string(b)}, nil
          }

          test case 如下:

          package mock

          import (
           "encoding/json"
           "reflect"
           "testing"

           "github.com/agiledragon/gomonkey"
           "github.com/stretchr/testify/assert"
          )

          func TestExec(t *testing.T) {
           var test = []struct {
            in   []byte
            want *Response
           }{
            {
             in:   []byte("https://gocn.vip/api/v1/count"),
             want: &Response{Result: "666"},
            },
           }
           var r Request
           f := func(t *testing.T) *gomonkey.Patches {
            patches := gomonkey.NewPatches()
            // mock json.Unmarshal()
            patches.ApplyFunc(json.Unmarshal, func(b []byte, d interface{}) error {
             data := d.(*Request)
                // 替換成任何你想要的數(shù)據(jù)
             (*data).Url = "127.0.0.1/api/v1/count"
             return nil
            })
            // mock 成員方法,注意,成員方法首字母要大寫!
            patches.ApplyMethod(reflect.TypeOf(&r), "DoAction"func(_ *Request, _ string) (*Response, error) {
             return &Response{Result: "666"}, nil
            })
            return patches
           }
           t.Run("test"func(t *testing.T) {
            patches := f(t)
            defer patches.Reset()
            for _, v := range test {
             r, err := exec(v.in)
             if !assert.NotNil(t, r) {
              t.Log(err)
              continue
             }
             assert.Equal(t, "666", r.Result)
            }
           })
          }
          $ go test -gcflags=-l -v -run ./
          === RUN   TestExec
          === RUN   TestExec/test
          --- PASS: TestExec (0.00s)
              --- PASS: TestExec/test (0.00s)
          PASS
          ok      mytest/add      0.018s

          當(dāng)然有時候也為了增加代碼覆蓋率,需要將if err != nil 等覆蓋,可以寫多個 f, 如

          f1 := func(t *testing.T) *gomonkey.Patches {}

          f2 := func(t *testing.T) *gomonkey.Patches {}

          最后 t.Run("test1",xxx), t.Run("test2", xxx)即可

          參考資料

          • https://github.com/agiledragon/gomonkey/
          • https://github.com/stretchr/testify

          《酷Go推薦》招募:


          各位Gopher同學(xué),最近我們社區(qū)打算推出一個類似GoCN每日新聞的新欄目《酷Go推薦》,主要是每周推薦一個庫或者好的項(xiàng)目,然后寫一點(diǎn)這個庫使用方法或者優(yōu)點(diǎn)之類的,這樣可以真正的幫助到大家能夠?qū)W習(xí)到

          新的庫,并且知道怎么用。


          大概規(guī)則和每日新聞類似,如果報(bào)名人多的話每個人一個月輪到一次,歡迎大家報(bào)名!戳「閱讀原文」,即可報(bào)名


          掃碼也可以加入 GoCN 的大家族喲~



          瀏覽 66
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉操逼逼 | 日韩一级特 | 好看一区二区三区 | 亚洲日韩精品视频久久 | 亚洲无码草逼逼 |