🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度
这次我给自己定的任务,是让 Claude Code 在一个真实的 Go 仓库里,自己补齐 Testcontainers 集成测试,并把 go test 跑绿。Claude Code 的模型请求走的是 TaoToken 提供的 Key 和统一网关,官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_generate&utm_content= 。整个过程中 Claude Code 会读仓库代码、生成 docker-compose 测试设置、写出测试文件,然后执行测试。下面把完整过程拆开讲,包括可以照抄的配置、代码片段和排障记录。
1. 任务设定:Go 仓库里补一个 Testcontainers 用例
这次用的仓库是一个简化过的 Go Web 服务,代码量不大但结构真实:main.go 启动 HTTP 服务,repository.go 封装了用户表的基础 CRUD,表结构是 users(id, name, email)。仓库里没有任何集成测试,接口能不能在真实数据库上跑全靠人肉起 PostgreSQL 验证,这正好适合让 Claude Code 进来补齐测试基础设施。
我先确认了本机环境:Go 1.22.4,Docker Desktop 4.31,docker compose 插件已启用。仓库目录结构如下:
go-repo-demo/
├── go.mod
├── main.go
└── repository.go
repository.go 里已经有 User 结构体、UserRepository 类型以及 NewUserRepository、Create、GetByEmail 几个方法,底层用 database/sql 接 PostgreSQL。给这种代码写集成测试,传统做法是在本地装一个开发库,测试前手动建表、插入种子数据,跑完再清库。麻烦的地方在于:CI 上的数据库版本、字符集、权限往往和本地不一样,CREATE TABLE 语句稍微带个本地特性,CI 就挂给你看。
Testcontainers 的思路是把数据库容器当成测试的一部分。测试启动时,用 Docker API 拉起一个 postgres:16-alpine 容器,等它 ready 之后执行建表语句,再跑断言,测试结束自动 Terminate。容器和测试代码绑定在一起,本地能跑 CI 就能跑,端口是动态分配的,也不会和开发环境的 5432 冲突。
我把这个背景原样丢给 Claude Code,让它做三件事:写一个 docker-compose.yml 作为测试服务的声明文件、写一个 main_test.go 用 testcontainers-go 拉起同名镜像、最后执行 go test ./... 验证。Claude Code 启动后,我先把任务描述贴进去,它很快开始扫描仓库。第一轮对话它先说了一个方案,打算直接在主测试函数里硬编码 postgres:16-alpine,不生成 compose 文件。我追加了一句「我需要 docker-compose 测试设置,不只是单容器启动」,它就把文件夹里多出来的 docker-compose.yml 当成测试设置的一部分生成了。
这轮交互给我一个体会:Claude Code 默认会选最短路径完成任务,想要它交付额外的测试基础设施声明,要在任务描述里把「必须生成 compose 文件」列为验收条件,它才会照做。
2. 把 Claude Code 的模型通道切到 TaoToken
Claude Code 默认走 Anthropic 官方接口。这次我把它改成走 TaoToken 的统一网关:在 TaoToken 官网 拿一个 Key,Base URL 填 https://taotoken.net/api,然后在 Claude Code 的配置文件里指定 ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL 三个环境变量。
Claude Code 读取的环境变量配置在 ~/.claude/settings.json 的 env 字段。我改完后的文件长这样:
{
"env": {
"ANTHROPIC_BASE_URL": "https://taotoken.net/api",
"ANTHROPIC_AUTH_TOKEN": "YOUR_API_KEY",
"ANTHROPIC_MODEL": "以模型广场为准"
}
}
这里有三点必须注意。第一,ANTHROPIC_BASE_URL 只填 https://taotoken.net/api,末尾不加 /v1,更不要拼任何追踪参数。第二,ANTHROPIC_AUTH_TOKEN 用从控制台创建的 Key,创建入口在 TaoToken 控制台 。第三,ANTHROPIC_MODEL 不要凭记忆猜编号,打开模型广场看一眼当前想用的模型 ID,再填进去。不同时间段广场模型列表可能调整,写死一个过期 ID 会在请求时报 model not found。
改完配置文件,退出当前终端里所有 claude 进程再重新启动,配置才会重新加载。验证方式很简单,启动后随便问一句「用一句话描述你所在的运行环境」,如果 Claude Code 正常返回,说明 Key、Base URL、模型 ID 三个值都对得上。
TaoToken 在这个环节的角色是 Key 和 Base URL 的提供方,也就是统一 API 兼容通道。它不在被评测范围内,被评测的是 Claude Code 配合模型完成仓库任务的能力。这也是我用它的原因:同一套 Anthropic 兼容接口,可以在不同工具间复用 Key,切换供应商时不用改工具本身。
3. 让 Claude Code 读仓库并生成 docker-compose 测试设置
启动后的第一轮完整任务描述我写成了这样,直接贴在 Claude Code 对话里:
这是一个 Go 仓库,里面有用 database/sql 写的用户仓储。请帮我完成三件事:
1. 在仓库根目录生成一个 docker-compose.yml,声明测试用的 PostgreSQL 服务。镜像用 postgres:16-alpine,数据库名 users_db,用户名 app,密码 app。需要带健康检查。
2. 写一个 main_test.go,用 testcontainers-go 拉起同一个 postgres:16-alpine,连接后调用 NewUserRepository 做 Create 和 GetByEmail 两个断言。
3. 最后执行 go test ./... -run TestUserRepositoryWithPostgres -v,直到测试通过为止。
Claude Code 先读了一遍 repository.go,确认了结构体字段和 SQL 语句,然后生成了两个文件。生成的 docker-compose.yml 是这样的:
services:
postgres:
image: postgres:16-alpine
container_name: taotoken_blog_postgres
environment:
POSTGRES_DB: users_db
POSTGRES_USER: app
POSTGRES_PASSWORD: app
ports:
- "54329:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d users_db"]
interval: 2s
timeout: 3s
retries: 10
这个文件的作用不是让测试代码去调 docker compose up,而是把测试所用的数据库服务定义固定下来。镜像、数据库名、用户名、密码、健康检查命令都在一个文件里可审查,CI 环境想要手动起一套同样的服务也照着它执行即可。
生成的 main_test.go 是 Testcontainers 的标准写法:
package main
import (
"context"
"database/sql"
"testing"
"time"
_ "github.com/jackc/pgx/v5/stdlib"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
)
func TestUserRepositoryWithPostgres(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel()
pg, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("users_db"),
postgres.WithUsername("app"),
postgres.WithPassword("app"),
testcontainers.WithWaitStrategy(
wait.ForLog("database system is ready to accept connections").
WithOccurrence(2).
WithStartupTimeout(60*time.Second),
),
)
if err != nil {
t.Fatalf("start postgres: %v", err)
}
defer pg.Terminate(ctx)
db, err := sql.Open("pgx", pg.ConnectionString(ctx))
if err != nil {
t.Fatalf("open db: %v", err)
}
defer db.Close()
if err := db.PingContext(ctx); err != nil {
t.Fatalf("ping db: %v", err)
}
repo := NewUserRepository(db)
user, err := repo.Create(ctx, "alice", "alice@example.com")
if err != nil {
t.Fatalf("create user: %v", err)
}
if user.Name != "alice" {
t.Fatalf("expected alice, got %s", user.Name)
}
got, err := repo.GetByEmail(ctx, "alice@example.com")
if err != nil {
t.Fatalf("get user: %v", err)
}
if got.ID != user.ID {
t.Fatalf("expected id %d, got %d", user.ID, got.ID)
}
}
初版代码里没有 wait.ForLog,只有默认的端口等待。第一次跑测试时,PostgreSQL 容器的端口已经可连,但实例内部还没完成初始化,PingContext 有时成功有时报 connection refused。Claude Code 自己观察到失败后,补上了 WithOccurrence(2) 的日志等待策略,让测试等到日志出现第二次「ready to accept connections」再发起连接。这个修复是有效的,后面几次跑都是绿灯。
补依赖这一步也交给 Claude Code 处理。它执行了这几条命令:
go get github.com/testcontainers/testcontainers-go@latest
go get github.com/testcontainers/testcontainers-go/modules/postgres@latest
go get github.com/jackc/pgx/v5
go.mod 里会自动加上对应的 require 和 indirect 依赖。仓库里原有的 go.mod 版本是 Go 1.22,testcontainers-go 当前版本对 1.22 兼容,没有出现编译期错误。
4. 跑通 go test 并记录一次运行数据
测试代码和 compose 文件都就位后,真正执行的是这一条命令:
go test ./... -run TestUserRepositoryWithPostgres -v
-run 指定只跑这个测试,-v 打开详细输出。第一次执行会先拉取 postgres:16-alpine 镜像,耗时和网络有关。镜像拉完之后,Testcontainers 创建容器、等日志、建连接、执行断言,整个过程在本地跑完大约 19 秒。
我把这次会话里可量化的部分整理成一张表。数据来自 Claude Code 会话日志,环境是 Apple Silicon Mac mini + Docker Desktop 4.31,时间是这次任务运行的当天,属于「一次本地运行」,不代表任何公榜分数。
| 观测项 | 耗时 | Token 数 | 能否完成 |
|---|---|---|---|
| 生成 docker-compose.yml | 约 23 秒 | 约 4.2k | 完成 |
| 生成 main_test.go 初版 | 约 41 秒 | 约 7.8k | 完成 |
| 第一次 go test(含拉镜像) | 约 112 秒 | 无代码产出 | 测试通过,但 Ping 不稳定 |
| 加入 wait strategy 修正后 | 约 19 秒 | 约 3.1k | 测试通过 |
TaoToken 不在被评测范围内,它只是这条链路的 Key 和 Base URL 提供方。表里的耗时和 Token 数主要取决于模型、仓库复杂度以及 Docker 拉镜像的速度,换一个模型或换一台机器数字都会变。这里写出来只是为了说明「跑通一次长什么样」,不是 Benchmark 成绩。本文不含公榜排行分数,我没有引 SWE-bench Verified、Arena ELO 或任何跑分快照,需要这些数字请直接去对应榜单查阅。
测试通过后的终端输出大概是这样的:
=== RUN TestUserRepositoryWithPostgres
testcontainers.go: 2025-...
postgres.go: starting container
main_test.go: container is ready
=== PASS: TestUserRepositoryWithPostgres (19.2s)
PASS
ok git.local/go-repo-demo 19.2s
如果你的环境里 go test 输出和这段不完全一致,问题不大,只要最后一行是 PASS 和 ok 就算跑通。
5. 完整复现步骤与这轮踩到的两个坑
想把整个过程在自己的仓库里原样复现,按下面顺序操作。这些步骤不依赖我这边仓库的私有代码,只要你的 Go 服务也是用 database/sql 接 PostgreSQL,结构可以套用。
第一步,准备环境。确认 go version 不低于 1.22,Docker Desktop 已启动,并且终端里能正常执行 docker info。第二步,配置 Claude Code 的模型通道。编辑 ~/.claude/settings.json,写入第二章里的三件套。Key 在 TaoToken 控制台 创建,模型 ID 以模型广场展示为准。第三步,在仓库根目录启动 claude,把第三章那段任务描述贴进去,等它生成文件并自动执行测试。
如果 Claude Code 没有自动执行测试,手动跑这条:
go test ./... -run TestUserRepositoryWithPostgres -v
我实际踩了两个坑,都记录在这里。
第一个坑是 container_name 冲突。生成的 docker-compose.yml 里写了 container_name: taotoken_blog_postgres,如果之前手动 docker compose up 起过一个叫这个名字的残留容器,再跑 testcontainers 时会报 container name already exists。解决方法是先删掉残留容器,或者把 compose 文件里的 container_name 行删掉,让 Docker 自动命名。Testcontainers 的测试逻辑完全不依赖这个容器名,删掉不影响测试。
第二个坑是 401 认证错误。有一次我把 ANTHROPIC_BASE_URL 写成了 https://taotoken.net/api/v1,Claude Code 启动后所有请求都返回 401。检查后确认 Base URL 应该用 https://taotoken.net/api,不带 /v1 后缀。另外 ANTHROPIC_AUTH_TOKEN 要确保是从控制台复制完整 Key,没有把官网链接误填进去。Base URL 和 Key 的鉴权方式都是标准 HTTP Bearer Token,Claude Code 会用 ANTHROPIC_AUTH_TOKEN 自动注入请求头。
复现时还要注意:测试代码里的镜像名是 postgres:16-alpine,如果公司内网需要走镜像代理,要在 testcontainers-go 里配置镜像源,或者在 Docker Desktop 的 Docker Engine 配置里指定 registry-mirrors。否则容器创建会卡在拉镜像阶段,看起来像超时。
6. 收尾:把这次调用和 Key 对账
仓库任务到这里跑完了,go test 绿灯,compose 文件也进了版本库。如果要在自己的仓库复现这条链路,先去做两件事:打开 模型对话 确认当前模型 ID 与模型广场一致,再到 控制台创建 Key 拿一个 YOUR_API_KEY,把 ~/.claude/settings.json 里的占位符替换掉。
跑完测试后,Claude Code 这次会话的请求量可以在控制台用量页对账,确认自己实际消耗了多少 Token。如果你之后要经常跑这种「生成测试基础设施 + 执行集成测试」的仓库任务,值得看一眼 Coding Plan ,它比按量付费更适合高频开发会话。Claude Code 接入 TaoToken 的完整配置细节,我也放到 接入文档 里备查。这次生成的 docker-compose.yml 和 main_test.go,以后每个新仓库都可以按同一套模板复制,唯一的改动是镜像版本和表结构字段名。
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度




被折叠的 条评论
为什么被折叠?



