Go内置了强大的测试框架,通过testing包提供单元测试、基准测试和示例测试功能。
_test.go结尾Test开头Benchmark开头Example开头// math.go
package math
func Add(a, b int) int {
return a + b
}
func Multiply(a, b int) int {
return a * b
}
// math_test.go
package math
import "testing"
func TestAdd(t *testing.T) {
result := Add(2, 3)
expected := 5
if result != expected {
t.Errorf("Add(2, 3) = %d; want %d", result, expected)
}
}
func TestMultiply(t *testing.T) {
result := Multiply(3, 4)
expected := 12
if result != expected {
t.Errorf("Multiply(3, 4) = %d; want %d", result, expected)
}
}
# 运行当前目录的所有测试
go test
# 运行所有包的测试
go test ./...
# 运行特定测试
go test -run TestAdd
# 显示详细输出
go test -v
# 显示测试覆盖率
go test -cover
# 生成覆盖率报告
go test -coverprofile=coverage.out
go tool cover -html=coverage.out
表格驱动测试是Go中最常用的测试模式,通过测试用例表来组织测试数据。
package math
import "testing"
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
expected int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -2, -3, -5},
{"mixed numbers", -2, 3, 1},
{"zero", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Add(tt.a, tt.b)
if result != tt.expected {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, result, tt.expected)
}
})
}
}
func assertEqual(t *testing.T, got, want int) {
t.Helper() // 标记为辅助函数,错误报告会指向调用者
if got != want {
t.Errorf("got %d, want %d", got, want)
}
}
func TestAdd(t *testing.T) {
result := Add(2, 3)
assertEqual(t, result, 5)
}
func TestMain(m *testing.M) {
// Setup
fmt.Println("测试前的准备工作")
// 运行测试
code := m.Run()
// Teardown
fmt.Println("测试后的清理工作")
os.Exit(code)
}
func TestMath(t *testing.T) {
t.Run("Add", func(t *testing.T) {
if Add(2, 3) != 5 {
t.Error("Add failed")
}
})
t.Run("Multiply", func(t *testing.T) {
if Multiply(2, 3) != 6 {
t.Error("Multiply failed")
}
})
}
// 运行特定子测试
// go test -run TestMath/Add
基准测试用于测量代码的性能。
func BenchmarkAdd(b *testing.B) {
for i := 0; i < b.N; i++ {
Add(2, 3)
}
}
func BenchmarkMultiply(b *testing.B) {
for i := 0; i < b.N; i++ {
Multiply(2, 3)
}
}
// 运行基准测试
// go test -bench=.
// go test -bench=BenchmarkAdd
func BenchmarkStringConcat(b *testing.B) {
b.ResetTimer() // 重置计时器,排除准备工作的时间
for i := 0; i < b.N; i++ {
_ = "hello" + "world"
}
}
func BenchmarkStringBuilder(b *testing.B) {
for i := 0; i < b.N; i++ {
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString("world")
_ = sb.String()
}
}
// 运行基准测试并显示内存分配
// go test -bench=. -benchmem
func BenchmarkParallel(b *testing.B) {
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
// 测试代码
Add(2, 3)
}
})
}
# 生成覆盖率文件
go test -coverprofile=coverage.out
# 查看覆盖率
go tool cover -func=coverage.out
# 生成HTML报告
go tool cover -html=coverage.out
# 按包显示覆盖率
go test -cover ./...
// calculator.go
package calculator
func Divide(a, b int) (int, error) {
if b == 0 {
return 0, errors.New("division by zero")
}
return a / b, nil
}
// calculator_test.go
func TestDivide(t *testing.T) {
tests := []struct {
name string
a, b int
want int
wantError bool
}{
{"normal", 10, 2, 5, false},
{"divide by zero", 10, 0, 0, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Divide(tt.a, tt.b)
if tt.wantError {
if err == nil {
t.Error("expected error, got nil")
}
} else {
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if got != tt.want {
t.Errorf("got %d, want %d", got, tt.want)
}
}
})
}
}
// user.go
type UserStore interface {
GetUser(id int) (*User, error)
}
type UserService struct {
store UserStore
}
func (s *UserService) GetUserName(id int) (string, error) {
user, err := s.store.GetUser(id)
if err != nil {
return "", err
}
return user.Name, nil
}
// user_test.go
type MockUserStore struct {
users map[int]*User
}
func (m *MockUserStore) GetUser(id int) (*User, error) {
user, ok := m.users[id]
if !ok {
return nil, errors.New("user not found")
}
return user, nil
}
func TestGetUserName(t *testing.T) {
mock := &MockUserStore{
users: map[int]*User{
1: {ID: 1, Name: "Alice"},
},
}
service := &UserService{store: mock}
name, err := service.GetUserName(1)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if name != "Alice" {
t.Errorf("got %s, want Alice", name)
}
}
示例测试既是测试也是文档。
func ExampleAdd() {
result := Add(2, 3)
fmt.Println(result)
// Output: 5
}
func ExampleMultiply() {
result := Multiply(3, 4)
fmt.Println(result)
// Output: 12
}