Go 测试

1. 测试文件的组织

在 Go 中,测试文件通常与被测试的源文件位于同一包内,并遵循以下命名规范:

  • 源文件xxx.go
  • 测试文件xxx_test.go

测试文件的命名必须以 _test.go 结尾,这样 Go 工具链才能识别并将其作为测试文件处理。

2. 测试函数的签名

测试函数必须满足以下签名:

go 复制代码
func TestXxx(t *testing.T) { ... }
  • 函数名以 Test 开头,后面跟被测试的函数或功能名称(通常首字母大写)。
  • 接受一个参数 *testing.T,用于报告测试失败和日志信息。

二、编写测试函数

1. 基本示例

假设有一个简单的加法函数 Add,位于 math.go 文件中:

go 复制代码
// math.go
package mathutil

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

对应的测试文件 math_test.go 可以这样编写:

go 复制代码
// math_test.go
package mathutil

import (
    "testing"
)

func TestAdd(t *testing.T) {
    tests := []struct {
        a, b, expected int
    }{
        {1, 2, 3},
        {0, 0, 0},
        {-1, 1, 0},
    }

    for _, tt := range tests {
        result := Add(tt.a, tt.b)
        if result != tt.expected {
            t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
        }
    }
}

2. 使用子测试

Go 1.7 引入了子测试(subtests),使得在同一个测试函数中运行多个相关测试更加方便:

go 复制代码
func TestAdd(t *testing.T) {
    tests := []struct {
        a, b, expected int
    }{
        {1, 2, 3},
        {0, 0, 0},
        {-1, 1, 0},
    }

    for _, tt := range tests {
        t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

3. 使用表驱动测试

表驱动测试是一种常见的测试模式,通过定义一组输入和预期输出来测试函数的行为:

go 复制代码
func TestMultiply(t *testing.T) {
    tests := []struct {
        a, b, expected int
    }{
        {2, 3, 6},
        {0, 5, 0},
        {-2, 4, -8},
    }

    for _, tt := range tests {
        t.Run(fmt.Sprintf("%d*%d", tt.a, tt.b), func(t *testing.T) {
            result := Multiply(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Multiply(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

三、运行测试

1. 使用 go test 命令

在包含测试文件的包目录下,运行以下命令即可执行所有测试:

bash 复制代码
go test

2. 运行特定测试

要运行特定的测试函数,可以使用 -run 参数,支持正则表达式:

arduino 复制代码
go test -run TestAdd

3. 查看详细输出

使用 -v 标志可以查看每个测试函数的详细输出:

bash 复制代码
go test -v

4. 并行运行测试

使用 t.Parallel() 可以让测试函数并行执行,提高测试效率:

scss 复制代码
func TestSomething(t *testing.T) {
    t.Parallel()
    // 测试代码
}

运行测试时,可以使用 -parallel 指定并行执行的测试数量:

bash 复制代码
go test -parallel 4

5.测试覆盖率

  • 使用 go test -cover 查看测试覆盖率。

  • 生成覆盖率文件:

    ini 复制代码
    go test -coverprofile=coverage.out 
    go tool cover -html=coverage.out 

示例:完整的测试流程

以下是一个综合示例,展示如何编写、运行和检查测试覆盖率。

1. 源代码

go 复制代码
// mathutil/math.go
package mathutil

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

func Multiply(a, b int) int {
    return a * b
}

2. 测试代码

go 复制代码
// mathutil/math_test.go
package mathutil

import (
    "testing"
)

func TestAdd(t *testing.T) {
    tests := []struct {
        a, b, expected int
    }{
        {1, 2, 3},
        {0, 0, 0},
        {-1, 1, 0},
    }

    for _, tt := range tests {
        t.Run(fmt.Sprintf("%d+%d", tt.a, tt.b), func(t *testing.T) {
            result := Add(tt.a, tt.b)
            if result != tt.expected {
                t.Errorf("Add(%d, %d) = %d; expected %d", tt.a, tt.b, result, tt.expected)
            }
        })
    }
}

3. 运行测试和覆盖率

ini 复制代码
go test -v -coverprofile=coverage.out
go tool cover -html=coverage.out

Go 提供了强大而简洁的测试工具,使得编写和维护测试变得非常方便。通过合理组织测试文件、编写可测试的代码、以及定期检查测试覆盖率,开发者可以确保代码的质量和可靠性。结合持续集成流程,自动化测试更是保障项目稳定性的重要手段。

相关推荐
程序员爱钓鱼1 小时前
Go Modules 包管理详解:go.mod、go.sum 与依赖管理
前端·后端·go
小满zs7 小时前
Go语言第三章(五谷轮回)
后端·go
江湖十年20 小时前
Go 语言中 YAML to JSON 踩坑笔记
后端·go·json
程序员爱钓鱼1 天前
第一个 Go 程序:Hello World
前端·后端·go
名字还没想好☜1 天前
Go 的 select 实战:超时、非阻塞收发与优雅退出的三个套路
开发语言·数据库·golang·go·并发
Java开发追求者2 天前
Go环境开发配置
go·go环境开发配置·环境开发配置
程序员爱钓鱼2 天前
配置 GoLand 与 VS Code 开发环境
前端·后端·go
fcu3dx3 天前
Go + PostgreSQL 餐饮SaaS后端架构:从单体到多租户的实战重构
go
程序员爱钓鱼3 天前
Go 开发环境安装(Windows、macOS、Linux)
后端·面试·go
ArixBit4 天前
用 Go 手撸 Agent 框架 #11:工具从哪里来——内置工具、MCP 与 Skills
go·agent