GOLANG測試必須用帶堆疊的errors

winlin發表於2017-06-22

GOLANG測試時,可以用匿名物件填充測試序列,但是如果沒有帶堆疊的errors,那麼會造成出現錯誤時無法排查。

GOLANG初始化匿名結構的方式,可以很方便的建立測試集合。

先看測試序列的填充,參考tricks-2015這個文章,怕你翻不了牆,我把內容貼上過來就是:

Anonymous structs: test cases (1/2)

These properties enable a nice way to express test cases:

func TestIndex(t *testing.T) {
    var tests = []struct {
        s   string
        sep string
        out int
    }{
        {"", "", 0},
        {"", "a", -1},
        {"fo", "foo", -1},
        {"foo", "foo", 0},
        {"oofofoofooo", "f", 2},
        // etc
    }
    for _, test := range tests {
        actual := strings.Index(test.s, test.sep)
        if actual != test.out {
            t.Errorf("Index(%q,%q) = %v; want %v", test.s, test.sep, actual, test.out)
        }
    }
}

是的,看起來很方便,出錯時也知道哪裡的問題,但是實際上如果序列中有函式,那就悲劇了。讓我們來試試,考慮一個包頭的定義,它就是兩個欄位,然後序列化成[]byte

type MyHeader struct {
    Version uint8
    Size uint16
}

func (v MyHeader) MarshalBinary() ([]byte, error) {
    return []byte{byte(v.Version),0,0},nil // Failed.
}

為了測試設定不同的值,得到不同的位元組,我們用兩個函式來填充測試序列:

func TestMyHeader_MarshalBinary(t *testing.T) {
    mhs := []struct {
        set     func(h *MyHeader)
        compare func(p []byte) error
    }{
        {func(h *MyHeader) { h.Size = 1 }, func(p []byte) error {
            if p[1] != 0x01 {
                return fmt.Errorf("p[1] is %v", p[1])  // line 194
            }
            return nil
        }},
        {func(h *MyHeader) { h.Size = 2 }, func(p []byte) error {
            if p[1] != 0x02 {
                return fmt.Errorf("p[1] is %v", p[1])  // line 200
            }
            return nil
        }},
    }
    for _, mh := range mhs {
        h := &MyHeader{}
        mh.set(h)
        if b, err := h.MarshalBinary(); err != nil {
            t.Errorf("error is %+v", err)
        } else if err = mh.compare(b); err != nil {
            t.Errorf("invalid data, err is %+v", err) // line 211
        }
    }
}

結果我們就懵逼了,出現的錯誤行數都是在error那個地方211行是不夠的,還需要知道是194還是200出問題了:

--- FAIL: TestMyHeader_MarshalBinary (0.00s)
    iprouter_test.go:211: invalid data, err is p[1] is 0
    iprouter_test.go:211: invalid data, err is p[1] is 0

怎麼辦呢?把堆疊資訊帶上,參考錯誤最佳實踐,改成這樣:

import oe "github.com/ossrs/go-oryx-lib/errors"

建立error時用這個package:

            if p[1] != 0x01 {
                return oe.Errorf("p[1] is %v", p[1])  // line 194
            }
            if p[1] != 0x02 {
                return oe.Errorf("p[1] is %v", p[1])  // line 200
            }

結果可以看到詳細的堆疊:

    iprouter_test.go:211: invalid data, err is p[1] is 0
        _/Users/winlin/git/test/src/core.TestMyHeader_MarshalBinary.func4
            /Users/winlin/git/test/src/core_test.go:200
        _/Users/winlin/git/test/src/core.TestMyHeader_MarshalBinary
            /Users/winlin/git/test/src/core_test.go:210
        testing.tRunner
            /usr/local/Cellar/go/1.8.1/libexec/src/testing/testing.go:657
        runtime.goexit
            /usr/local/Cellar/go/1.8.1/libexec/src/runtime/asm_amd64.s:2197

這樣可以巢狀非常多的函式做測試了。

相關文章