1. 网格测试
函数或方法的输出因收到的输入而异,如果为每个输入专门编写一个测试用例,将导致大量的重复代码。
不妨将输入的各种组合存放在网格之中,只编写一个测试用例即完成对所有输入的测试,比如象下面这样:
var greetingTests = []greetingTest{
{"en-US", "George", "Hello George!"},
{"fr-FR", "Chloé", "Bonjour Chloé!"},
{"it-IT", "Giuseppe", "Ciao Giuseppe!"},
}
// 网格测试
// 源代码
// Package greeting return greeting
package greeting
func translate(locale string) string {
switch locale {
case "en-US":
return "Hi "
case "fr-FR":
return "Bonjour "
case "it-IT":
return "Ciao "
default:
return "Hello "
}
}
// Greeting return greeting
func Greeting(locale, name string) string {
return translate(locale) + name + "!"
}
// 源代码对应的测试用例(测试输入为我们之前定义的网格)
// 函数或方法的输出因收到的输入而异,如果为每个输入专门编写一个测试用例,将导/// 致大量的重复代码。不妨将输入的各种组合存放在网格之中,只编写一个测试用例即
// 完成对所有输入的测试
package greeting
import "testing"
type greetingTest struct {
locale string
name string
expected string
}
var greetingTests = []greetingTest{
{"en-US", "George", "Hello George!"}, // 与源代码不一致,会失败
{"fr-FR", "Chloé", "Bonjour Chloé!"},
{"it-IT", "Giuseppe", "Ciao Giuseppe!"},
}
func TestGreeting(t *testing.T) {
for _, test := range greetingTests {
actual := Greeting(test.locale, test.name)
if actual != test.expected {
t.Fatalf(
"Greeting(%q,%q)->%q, expected %q",
test.locale, test.name, actual,
test.expected)
}
}
}
// 打印输出:
greeting_test.go:29: Greeting("en-US","George")->"Hi George!", expected "Hello George!"
2. 基准测试
Go语言提供了功能强大的基准测试框架,利用该框架开发人员可以精确地获知,选择何种方式能使程序完成特定任务的性能最优。
基准测试函数的函数名以"Benchmark"开头,接受一个类型为B的参数。
- func ByPlus(strs ...string) string { ... }
- func BenchmarkByPlus(b *testing.B) { ... }
在测试函数内部,使用循环反复地调用被测试函数以建立基准。
- for n := 0; n < b.N; n++ {
ByPlus("Hello", " ", "World", "!")
} - 循环的次数N无需指定,框架会自动设置它以获得可靠的数据集。(为了避免随机性,会执行N次求平均值来衡量性能)
基准测试结束后,会生成一个测试报告,指出每个被测函数的总调用次数(N)和单次调用的平均耗时(单位ns)。
- BenchmarkByPlus-8 10000000 185 ns/op
在包目录下执行如下命令,启动基准测试:
- go test -bench
// 基准测试(测试了3种字符串拼接方法的效率)
// Package joinstrs join strings
package joinstrs
import (
"bytes"
"strings"
)
// ByPlus join strings by plus
func ByPlus(strs ...string) string {
s := ""
for _, str := range strs {
s += str
}
return s
}
// ByJoin join strings by join
func ByJoin(strs ...string) string {
return strings.Join(strs, "")
}
// ByBuff join strings by buffer
func ByBuff(strs ...string) string {
b := bytes.Buffer{}
for _, str := range strs {
b.WriteString(str)
}
return b.String()
}
// 基准测试(测试了3种字符串拼接方法的效率)
// 基准测试关注代码的运行性能。基准测试
// 函数的函数名必须以"Benchmark"开头
//
// 执行如下命令,启动基准测试:
// go test -bench .
package joinstrs
import "testing"
func TestByPlus(t *testing.T) {
// 使用了"testing包"小节所述的actual-expected模式
actual, expected := ByPlus(
"Hello", " ", "World", "!"),
"Hello World!"
if actual != expected {
t.Fatalf("Actual %q, expected %q",
actual, expected)
}
}
func TestByJoin(t *testing.T) {
actual, expected := ByJoin(
"Hello", " ", "World", "!"),
"Hello World!"
if actual != expected {
t.Fatalf("Actual %q, expected %q",
actual, expected)
}
}
func TestByBuff(t *testing.T) {
actual, expected := ByBuff(
"Hello", " ", "World", "!"),
"Hello World!"
if actual != expected {
t.Fatalf("Actual %q, expected %q",
actual, expected)
}
}
func BenchmarkByPlus(b *testing.B) { // 基准测试
for n := 0; n < b.N; n++ {
ByPlus("Hello", " ", "World", "!")
}
}
func BenchmarkByJoin(b *testing.B) {// 基准测试
for n := 0; n < b.N; n++ {
ByJoin("Hello", " ", "World", "!")
}
}
func BenchmarkByBuff(b *testing.B) {// 基准测试
for n := 0; n < b.N; n++ {
ByBuff("Hello", " ", "World", "!")
}
}
// 打印输出:
goos: windows
goarch: amd64
pkg: test/benchmark
BenchmarkByPlus-8 10000000 185 ns/op
BenchmarkByJoin-8 20000000 103 ns/op//字符串拼接strings.Join()是最高效的
BenchmarkByBuff-8 10000000 161 ns/op
PASS
ok test/benchmark 6.479s
3.测试覆盖率
测试覆盖率指被测试执行的代码占总代码的百分比。
- 单元测试通过,说明功能正确
- 基准测试效果也不错,说明性能可以接受
- 这并不表示被测软件经受住了考验,因为有些代码可能根本就没有被执行到
在包目录下执行如下命令,计算测试覆盖率:
- go test -cover
- 其是针对某一包目录下的所有go源文件中的func进行计算的
// 测试覆盖率指被测试执行的代码占总代码的百分比
//
// 执行如下命令,启动测试并输出覆盖率:
// go test -cover
package greeting
import "testing"
func TestGreeting(t *testing.T) {
actual, expected := Greeting("World"),
"Hello World!"
if actual != expected {
t.Fatalf("Actual %q, expected %q",
actual, expected)
}
}
// Package greeting return greeting
package greeting
// Greeting return greeting
func Greeting(s string) string {
return "Hello " + s + "!"
}
// Farewell return farewell
func Farewell(s string) string {
return "Goodbye " + s + "!"
}
// 打印输出:
PASS
coverage: 50.0% of statements
ok test/coverage 0.447s