第八章:工具链与生态——Go Modules 和测试

8.1 Go Modules 深入 #

我们之前用go mod init初始化了项目。现在来看看如何管理依赖。这就像PHP的Composer

  • 添加依赖: 你不需要手动编辑go.mod文件。只要在你的代码中import一个第三方包,然后在终端运行go tidygo get,Go工具链会自动下载它并更新go.modgo.sum文件。

    # 假设你在代码里 import "github.com/google/uuid"
    go mod tidy
    # 或者
    go get github.com/google/uuid
    

    go.mod会增加一行require github.com/google/uuid v1.6.0go.sum则记录了依赖包的哈希校验值,保证依赖不被篡改,类似composer.lock

  • 更新依赖: go get -u <package>

  • 清理无用依赖: go mod tidy

8.2 内置测试框架 #

Go内置了强大的测试工具,无需像PHPUnit那样单独安装。测试是Go文化的一等公民。

测试文件必须以_test.go结尾,并与被测试的代码放在同一个包下。

示例

假设我们有之前的mymath包:

// mymath/calculator.go
package mymath

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

我们可以为它编写一个测试:

// mymath/calculator_test.go
package mymath

import "testing" // 导入testing包

// 测试函数必须以 Test 开头,并接收一个 *testing.T 类型的参数
func TestAdd(t *testing.T) {
    // 定义一组测试用例
    testCases := []struct {
        name   string // 测试用例名
        a, b   int    // 输入
        want   int    // 期望的输出
    }{
        {"positive numbers", 2, 3, 5},
        {"negative numbers", -2, -3, -5},
        {"zero", 5, 0, 5},
    }

    // 遍历所有测试用例
    for _, tc := range testCases {
        // t.Run可以创建子测试
        t.Run(tc.name, func(t *testing.T) {
            got := Add(tc.a, tc.b) // 调用被测试的函数
            if got != tc.want {
                // 如果结果与期望不符,使用t.Errorf报告错误
                t.Errorf("Add(%d, %d) = %d; want %d", tc.a, tc.b, got, tc.want)
            }
        })
    }
}

运行测试

mymath目录下,运行:

go test

如果所有测试通过,你会看到ok

# 查看更详细的输出
go test -v

# 查看测试覆盖率
go test -cover
# --- PASS: TestAdd (0.00s)
#     --- PASS: TestAdd/positive_numbers (0.00s)
#     --- PASS: TestAdd/negative_numbers (0.00s)
#     --- PASS: TestAdd/zero (0.00s)
# PASS
# coverage: 100.0% of statements
# ok      your_module/mymath      0.002s

编写测试是Go工程师的日常,它能极大地保证代码质量和项目未来的可维护性。