← 返回博客
go2026-09-12 22:01:491 分钟 · 402 0

Gin 集成测试:testcontainers 起真依赖跑 CI

用 testcontainers-go 在测试里拉起真实 MySQL 和 Redis 容器,跑迁移和接口测试,再接到 GitHub Actions,让每次提交都过一遍真依赖。

#gin#集成测试#CI

第 10 篇的单元测试用 mock 替掉数据库,快但测不到真实 SQL、索引、事务。集成测试起真依赖,验证整条链路。以前要本地装 MySQL,现在用 testcontainers 在测试里拉容器,CI 上自动跑。

1. 为什么还要集成测试

mock 假设你的 SQL 是对的,但真实 MySQL 会咬类型、咬字段长度、咬外键。事务回滚、连接池行为也得真库才测得出。集成测试补这块盲区。

2. testcontainers 起 MySQL

测试里拉一个临时 MySQL 容器,用完自动销毁:

import "github.com/testcontainers/testcontainers-go"

func startMySQL(t *testing.T) string {
    ctx := context.Background()
    req := testcontainers.ContainerRequest{
        Image:        "mysql:8.0",
        ExposedPorts: []string{"3306/tcp"},
        Env:          map[string]string{"MYSQL_ROOT_PASSWORD": "pass", "MYSQL_DATABASE": "test"},
        WaitingFor:   wait.ForListeningPort("3306/tcp"),
    }
    c, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
        ContainerRequest: req, Started: true,
    })
    require.NoError(t, err)
    t.Cleanup(func() { c.Terminate(ctx) })

    host, _ := c.Host(ctx)
    port, _ := c.MappedPort(ctx, "3306")
    return fmt.Sprintf("root:pass@tcp(%s:%s)/test?parseTime=true", host, port.Port())
}

3. 测试里跑迁移再测

func TestCreateOrder_Integration(t *testing.T) {
    dsn := startMySQL(t)
    db, _ := gorm.Open(mysql.Open(dsn))
    db.AutoMigrate(&Order{}, &User{})

    repo := NewOrderRepo(db)
    svc := NewOrderSvc(repo)
    h := &OrderHandler{svc: svc}

    r := gin.New()
    r.POST("/orders", h.Create)
    w := httptest.NewRecorder()
    req, _ := http.NewRequest("POST", "/orders", strings.NewReader(`{"uid":1,"amount":100}`))
    req.Header.Set("Content-Type", "application/json")
    r.ServeHTTP(w, req)

    assert.Equal(t, 201, w.Code)
    var n int64
    db.Model(&Order{}).Count(&n)
    assert.Equal(t, int64(1), n)
}

真实落库,最后数行数确认写入,比 mock 可信。

4. 接 Redis 同理

Image: "redis:7",拿到地址后初始化 rdb,测缓存命中、失效那套逻辑。多个容器用同一个 ctx 管理生命周期。

5. GitHub Actions 跑 CI

name: test
on: [push]
jobs:
  integration:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with: { go-version: "1.27" }
      - run: go test -tags=integration ./... -cover

testcontainers 在 CI 里用 runner 自带的 Docker,不用额外装。给集成测试打 integration build tag,本地 go test 默认不拉容器,跑得快;CI 才带 tag 跑全套。

6. 上线清单

集成测试只在 CI 或显式 tag 下跑,别拖慢本地单测。容器用完 t.Cleanup 销毁,不占资源。迁移用同一份代码,保证测的是线上结构。敏感配置走 CI secret,不进仓库。覆盖率报告上传,低于阈值卡合并。

下一篇讲指标监控,把线上运行状态变成能看的曲线。

相关推荐

本文为原创文章,采用CC BY-NC-SA 4.0协议授权,转载请保留署名与原文链接。原文链接:https://www.wxbuluo.com/article/193