【Go Test】单元测试保姆级完整指南

前言

日常开发中,很多新手会用 空 main.go 手动调用函数/Handler 调试代码,这种方式效率极低、无法回归、不能自动化、不支持团队协作。

Go 语言原生自带完整测试框架,无需任何第三方库,是官方推荐的唯一测试方案。本文整合所有核心规则、目录规范、代码示例、实操命令、避坑要点,可直接收藏/发布博客长期复用。

一、Go 测试核心强制规则(必记)

1. 文件命名规则

测试文件必须以 \_test\.go 结尾

  • 业务文件:xxx\.go

  • 对应测试文件:xxx\_test\.go

2. 测试函数规则

  • 函数名必须以 Test 开头

  • 参数固定:\(t \*testing\.T\)

  • 无返回值、无参数自定义

标准格式:

Plain 复制代码
func TestXxx(t *testing.T) {
    // 测试逻辑
}

3. 目录存放规则(重点)

测试文件必须和被测试的业务文件【同目录、同包】

正确结构:

Plain 复制代码
项目目录/
├── calc.go        // 业务代码
├── calc_test.go   // 对应测试代码(同目录)
├── handler.go     // 业务代码
└── handler_test.go// 对应测试代码(同目录)

优势:无需导包、直接调用私有/公有方法

禁止:单独新建 test 文件夹存放测试文件(破坏包结构,不推荐)

4. 编译特性

所有 _test.go 文件不会被编译进生产二进制文件,零侵入业务代码。

二、测试命令运行目录 + 完整命令大全

1. 运行目录规则

  • 测试当前目录 代码:在当前业务目录执行 go test

  • 测试子目录 代码:根目录执行 go test \./子目录名

  • 测试整个项目所有包 :根目录执行 go test \./\.\.\.

2. 全套常用测试命令(日常必备)

Plain 复制代码
# 执行当前目录测试,展示详细日志
go test -v

# 只执行指定的某个测试函数
go test -v -run TestAdd

# 查看代码测试覆盖率
go test -cover

# 生成覆盖率文件,打开网页可视化查看
go test -coverprofile=cover.out && go tool cover -html=cover.out

# 递归测试项目所有包
go test ./... -v

三、实战示例1:普通函数单元测试

适用于:工具函数、计算函数、业务逻辑函数等通用场景

1. 业务代码 calc.go

Plain 复制代码
package demo

// Add 两数求和测试函数
func Add(a, b int) int {
    return a + b
}

// Sub 两数求差测试函数
func Sub(a, b int) int {
    return a - b
}

2. 测试代码 calc_test.go

采用表格驱动测试(Go 官方最佳实践,多用例统一管理)

Plain 复制代码
package demo

import "testing"

func TestAdd(t *testing.T) {
    // 定义多组测试用例:名称、入参、预期结果
    testCases := []struct {
        name string
        a    int
        b    int
        want int
    }{
        {"正数相加", 1, 2, 3},
        {"负数相加", -1, -2, -3},
        {"零值相加", 0, 99, 99},
    }

    // 遍历执行用例
    for _, tc := range testCases {
        // 子测试:单个用例失败不影响其他用例
        t.Run(tc.name, func(t *testing.T) {
            res := Add(tc.a, tc.b)
            // 断言校验结果
            if res != tc.want {
                t.Errorf("Add(%d,%d) = %d, 预期结果: %d", tc.a, tc.b, res, tc.want)
            }
        })
    }
}

3. 执行测试

进入当前目录执行:go test \-v

四、实战示例2:原生 HTTP Handler 测试

核心优势:无需启动服务器、无需监听端口,原生模拟 HTTP 请求/响应,极速测试接口逻辑

1. 业务代码 handler.go

Plain 复制代码
package demo

import (
    "encoding/json"
    "net/http"
)

type User struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
}

// GetUserHandler 原生HTTP接口
func GetUserHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    user := User{
        ID:   1,
        Name: "张三",
    }
    _ = json.NewEncoder(w).Encode(user)
}

2. 测试代码 handler_test.go

Plain 复制代码
package demo

import (
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
)

func TestGetUserHandler(t *testing.T) {
    // 1. 模拟HTTP请求
    req := httptest.NewRequest("GET", "/user", nil)
    // 2. 模拟响应记录器(捕获返回值)
    w := httptest.NewRecorder()

    // 3. 直接执行Handler逻辑
    GetUserHandler(w, req)

    // 4. 断言1:校验状态码
    if w.Code != http.StatusOK {
        t.Fatalf("状态码错误,实际:%d,预期:%d", w.Code, http.StatusOK)
    }

    // 5. 断言2:校验响应数据
    var resp User
    if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
        t.Fatalf("响应解析失败:%v", err)
    }

    if resp.ID != 1 || resp.Name != "张三" {
        t.Errorf("返回数据异常,实际数据:%+v", resp)
    }
}

五、实战示例3:Gin 框架 Handler 测试(高频场景)

适配绝大多数 Go 后端项目,写法通用、零改造

Plain 复制代码
package demo

import (
    "net/http"
    "net/http/httptest"
    "testing"

    "github.com/gin-gonic/gin"
)

// 测试Gin接口
func TestGinUserHandler(t *testing.T) {
    // 初始化Gin引擎
    r := gin.Default()
    r.GET("/user/:id", GetUserGinHandler)

    // 模拟请求
    req := httptest.NewRequest("GET", "/user/1", nil)
    w := httptest.NewRecorder()

    // 执行路由逻辑
    r.ServeHTTP(w, req)

    // 后续可自行添加状态码、数据断言,和上面示例一致
}

六、为什么放弃 main 手动测试?

  1. 可自动化:一行命令批量跑所有用例,无需手动运行

  2. 可回归:迭代代码后,一键校验旧功能是否报错

  3. 零成本:原生支持,无第三方依赖、不污染生产代码

  4. 可量化:支持测试覆盖率,清晰看到哪些代码未测试

  5. 可集成:完美适配 CI/CD 自动化部署流程

七、核心总结

  1. 规范:xxx\.go 对应 xxx\_test\.go,同目录同包

  2. 格式:测试函数 TestXxx\(t \*testing\.T\)

  3. 执行:当前目录 go test \-v,全局测试 go test \./\.\.\. \-v

  4. 普通函数:表格驱动测试 + 结果断言

  5. HTTP接口:httptest 模拟请求,无需启动服务

  6. 测试文件不编译进生产包,安全无副作用

(注:文档部分内容可能由 AI 生成)

相关推荐
UestcXiye11 小时前
GoogleTest 使用指南 | 单元覆盖率分析
c++·单元测试·googletest
霸道流氓气质11 小时前
Mockito 单元测试从入门到实战:Java Service 层测试完全指南
单元测试·mockito
审判长烧鸡1 天前
【Go工具】go-playground是什么组织?官方的?
开发语言·安全·go
别样的感动1 天前
我写了一个 Go 框架:用 DSL 替代 ORM,代码体积减半,开发效率翻倍
go
明月_清风1 天前
Go语言空接口与类型断言完全指南:从"万能容器"到"类型还原"
后端·go
蓝宝石的傻话1 天前
security-collector-exporter:用Prometheus 解决 Linux 的安全审计
go
tyung1 天前
Go 手写二叉堆优先队列:避开 container/heap 的性能陷阱
数据结构·后端·go
审判长烧鸡2 天前
【PHPer转Go】fmt vs log/slog
go·php
菠萝猫yena2 天前
【读书笔记】《测试架构师修炼之道》读书笔记
功能测试·测试工具·单元测试