www.zhblog.net

Go 测试包


Go 本身附带了testing包,搭配go test指令,可以自动对包中的代码进行测试,在包中,测试代码必须是 _test.go 结尾,一个包中可以有多个 _test.go,例如,fmt 包的源码中,可以看到 export_test.go、fmt_test.go 等,就是测试代码。

功能测试

想要使用 Go 的testing包编写测试代码,必须import "testing",在 _test.go 中编写形式func TestXxx(t *testing.T)的函数,Xxx 可以是任意名称,例如,在 src/mymath 目录中,写个 basic_test.go:

package mymath

import "testing"

func TestSomething(t *testing.T) {
    // write some test
}

接着只要执行go test mymath,就会自动寻找mymath包中的 _test.go 中 Test 开头的函数并执行,由于目前没编写任何测试内容,测试是以 PASS 结束。

Go 测试包

如果函数中使用了testingErrorFail等与失败相关的方法,那么测试就会失败,例如:

package mymath

import "testing"

func TestSomething(t *testing.T) {
    t.Fail()
}

Go 测试包

如果想要在测试失败时,留下一些消息,可以使用Error方法,例如:

package mymath

import "testing"

func TestSomething(t *testing.T) {
    t.Error("something wrong")
}

Go 测试包

来实际写个测试,例如,测试一个Add函数:

package mymath

import "testing"

func TestAdd(t *testing.T) {
    if Add(1, 2) == 3 {
        t.Log("mymath.Add PASS")
    } else {
        t.Error("mymath.Add FAIL")
    }
}

由于目前还没有编写Add函数,因此若执行go test mymath的话,会以 [build failed] 收场,如果在 basic.go 编写了正确的Add函数:

package mymath

func Add(a, b int) int {
    return a + b
}

不过,如果直接执行go test mymath的话,只会显示 ok 等字眼,不会显示Log的消息,想看到Log的消息的话,必须加上-v实参(代表 verbose),例如:

Go 测试包

如果Log之后接上Fail函数,那么不加上-v,也会显示Log的消息,实际上,Error函数就是相当于先以Log显示指定的消息,然后再接上Fail函数。

如果想要略过测试,那么可以使用Skip函数,例如:

package mymath

import "testing"

func TestSomething(t *testing.T) {
    t.Skip()
}

func TestAdd(t *testing.T) {
    if Add(1, 2) == 3 {
        t.Log("mymath.Add PASS")
    } else {
        t.Error("mymath.Add FAIL")
    }
}

TestSomething中如果没有执行Skip会是两个 PASS 的测试结果,若如上执行了Skip,会是一个 SKIP 与一个 PASS 的测试结果。例如:

Go 测试包

如果你想指定某个测试,可以使用-run实参,这接受一个正则表达式,例如,若只想执行TestAdd,那么可以如下:

Go 测试包

性能评测

如果想进行性能评测(Benchmark),那么 _test.go 中,评测函数必须是func BenchmarkXxx(b *testing.B)形式,例如:

package mymath

import "testing"

func TestSomething(t *testing.T) {
    t.Skip()
}

func TestAdd(t *testing.T) {
    if Add(1, 2) == 3 {
        t.Log("mymath.Add PASS")
    } else {
        t.Error("mymath.Add FAIL")
    }
}

func BenchmarkAdd(b *testing.B) {
    for i := 0; i < b.N; i++ {
        Add(1, 2)
    }
}

为了进行评测,被测试的函数要执行多次,以求得每次执行的平均时间,要执行多次函数可以使用循环,并以b.N作为边界,b.N目标默认是 1000000000,评测默认会在一秒内,以越来越大的b.N执行循环,这是为了让评测进入稳定状态,以收集到可靠的评测数据;如果运行时间到了,b.N目标值仍未达成,就以现有收集到的数据来回报评测结果。

你可以在执行go test时,加上-bench实参,这个实参后可以使用正则表达式,来指定符合的评测函数名称,例如,想执行所有评测函数,可以使用-bench="."

Go 测试包

评测的结果中显示,达到了b.N默认目标 100000000 次,平均每次循环花了 0.58 纳秒(nanosecond)。

如果只想进行性能评测,可以使用-run实参,这本来是用来指定要执行的测试函数,只要指定一个不符合任何测试函数的正则表达式,就可以略过所有测试,只执行评测函数了,例如:

Go 测试包

方才谈到,评测默认的运行时间是一秒,如果在这个时间内,无法达到b.N的目标值,可以增加这个时间,这要使用-benchtime实参,指定的格式像是 1h30s,例如:

Go 测试包

如果想固定b.N的值,Go 1.12 以后可以使用x后置,例如指定执行 100000000000 次(默认b.N目标的 10 倍)并收集结果:

Go 测试包

-count可以指定评测重启几次:

Go 测试包

想知道更多 Go 测试包的细节,可以参考Package testing的说明。


展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情