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

相关推荐
学习星球7 小时前
# 6G通感一体化(ISAC)技术深度解析——从原理到实战> <br />
go·信息与通信·媒体
小满zs10 小时前
Go语言第十章(指针)
后端·google·go
学习星球1 天前
6G核心网架构深度解析——AI Native时代的网络变革
网络·人工智能·5g·架构·go·信息与通信
ylj_dev2 天前
从 0 构建 AI Workload Platform(九):真实场景、最小控制台与开源发布
go·react·开源项目·工作流·ai agent
tyung2 天前
znet 数据编解码:字节流怎么变成消息
后端·网络协议·go
leeyi2 天前
数据库迁移不翻车:golang-migrate 实战,143 个 DDL 有序执行(第97篇-E83)
go·aigc·agent
用户330144867632 天前
mheap:全局堆管理器
go
用户330144867632 天前
10. Large 对象分配:直接路径
go
yinchnag2 天前
CRTP:奇异递归模板模式在 Go 模块系统中的实现
设计模式·go
ylj_dev3 天前
从 0 构建 AI Workload Platform(七):可观测性、故障注入与性能验证
go·prometheus·可观测性·opentelemetry·故障注入