基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill golang-testcontainers命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
| name | golang-testcontainers |
| description | Write Go integration tests with testcontainers-go Use when this capability is needed. |
| metadata | {"author":"brpaz"} |
Use this skill when writing or reviewing Go integration tests that need real infrastructure dependencies in Docker.
Use it together with golang-testing for general Go test structure, t.Parallel() defaults, black-box package guidance, and assertion style.
Unless there is a clear reason not to, prefer these defaults:
postgres.Run and redis.Run over lower-level generic setup when a module existstestcontainers.Run over older GenericContainer patterns for generic servicestestcontainers.CleanupContainer(t, ctr) in normal testsFor Postgres and Redis integration tests, prefer real Postgres and Redis containers.
These are not mocks.
If the test is meant to validate SQL, migrations, transactions, Redis commands, TTL behaviour, or networked dependency behaviour, a real container is usually the right tool.
github.com/testcontainers/testcontainers-go is the main libraryRun(...) APIsGenericContainer is the older style; prefer testcontainers.Run(...) for new generic-container examplesRunContainer(ctx, opts...) helpers are deprecated; prefer postgres.Run(...), redis.Run(...), etc.WithReuseByName(...) is experimental; do not make it your default CI/test strategyChoose container lifetime deliberately:
| Scope | Startup cost | Isolation | Parallel friendliness | Recommended use |
|---|---|---|---|---|
| Per test | Highest | Strongest | Excellent | Small suites, destructive tests, tests that mutate process-wide server state |
| Per package | Moderate | Strong if you isolate test data | Excellent when state is isolated correctly | Default for Postgres, Redis, and similar services |
| Cross-package/shared reusable container | Lowest warm-start cost | Weakest | Risky | Local experimentation only; avoid as the default |
For Postgres and Redis, prefer:
Why this is the usual sweet spot:
go test runs each package in a separate process, so package-scoped fixtures already isolate one package from anotherIf most tests in the package need the dependency, TestMain is a good fit. If only some tests need it, a lazy package-scoped helper can be better.
Use generic startup when there is no higher-level module or when you need custom behaviour.
package cache_test
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)
func TestWithGenericRedis(t *testing.T) {
t.Parallel()
ctx := context.Background()
ctr, err := testcontainers.Run(ctx,
"redis:7",
testcontainers.WithExposedPorts("6379/tcp"),
testcontainers.WithWaitStrategy(
wait.ForListeningPort("6379/tcp"),
wait.ForLog("Ready to accept connections").WithStartupTimeout(30*time.Second),
),
)
testcontainers.CleanupContainer(t, ctr)
require.NoError(t, err)
endpoint, err := ctr.Endpoint(ctx, "")
require.NoError(t, err)
_ = endpoint // pass to your client under test
}
Use this pattern for services without a dedicated module, or when you need full control over files, env vars, commands, or custom wait strategies.
Prefer the Postgres module for Postgres integration tests.
package repo_test
import (
"context"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
)
func TestRepositoryWithPostgres(t *testing.T) {
t.Parallel()
ctx := context.Background()
ctr, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("app_test"),
postgres.WithUsername("postgres"),
postgres.WithPassword("postgres"),
postgres.WithInitScripts(filepath.Join("testdata", "init.sql")),
postgres.BasicWaitStrategies(),
)
testcontainers.CleanupContainer(t, ctr)
require.NoError(t, err)
dsn, err := ctr.ConnectionString(ctx, "sslmode=disable")
require.NoError(t, err)
_ = dsn // open your DB client here
}
Notes:
postgres.BasicWaitStrategies() is the common default for Postgres readinessWithInitScripts(...) is useful for schema setup or seed dataConnectionString(...) is usually the easiest way to build a DB clientPrefer the Redis module for Redis integration tests.
package cache_test
import (
"context"
"testing"
"github.com/stretchr/testify/require"
"github.com/testcontainers/testcontainers-go"
tcredis "github.com/testcontainers/testcontainers-go/modules/redis"
)
func TestCacheWithRedis(t *testing.T) {
t.Parallel()
ctx := context.Background()
ctr, err := tcredis.Run(ctx,
"redis:7",
)
testcontainers.CleanupContainer(t, ctr)
require.NoError(t, err)
uri, err := ctr.ConnectionString(ctx)
require.NoError(t, err)
_ = uri // pass to your redis client under test
}
Notes:
WithConfigFile(...), WithTLS(), or WithLogLevel(...) when relevantConnectionString(...) returns a ready-to-use Redis URIWithSnapshotting(...) configures Redis persistence behaviour; it is not a per-test isolation/reset mechanismWhen most tests in a package need the same dependency, prefer a package-scoped container.
package repo_test
import (
"context"
"log"
"os"
"testing"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
)
var (
postgresDSN string
postgresCtr *postgres.PostgresContainer
)
func TestMain(m *testing.M) {
ctx := context.Background()
var err error
postgresCtr, err = postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("app_test"),
postgres.WithUsername("postgres"),
postgres.WithPassword("postgres"),
postgres.BasicWaitStrategies(),
)
if err != nil {
log.Fatal(err)
}
postgresDSN, err = postgresCtr.ConnectionString(ctx, "sslmode=disable")
if err != nil {
log.Fatal(err)
}
code := m.Run()
if err := testcontainers.TerminateContainer(postgresCtr); err != nil {
log.Printf("terminate postgres container: %v", err)
}
os.Exit(code)
}
This is a good default when:
Sharing one container does not make parallel tests safe by itself.
If tests run with t.Parallel(), they must not step on the same data.
Prefer one of these per-test isolation patterns.
Preferred order:
Best when the application code can accept a *sql.Tx, pgx.Tx, or a narrow query interface.
Good when each test can use a unique schema name.
The Postgres module supports Snapshot(...) and Restore(...).
Use it when:
Be careful:
Restore(...) resets shared database statePreferred order:
Good when using a standard standalone Redis image.
client := redis.NewClient(&redis.Options{
Addr: redisAddr,
DB: testDBNumber,
})
Guidance:
FLUSHDB for that logical DB onlyFLUSHALL in testsGood when DB-number isolation is unavailable or inconvenient.
t_<id>:Be careful with global Redis operations:
FLUSHALL will destroy every test's stateFLUSHDB is also unsafe if multiple parallel tests share the same logical DBThis is usually the best tradeoff for repository/service integration tests.
TestMainPrefer this over one-container-per-test when:
This is usually the best tradeoff for cache integration tests.
Do not assume container start means service readiness.
Prefer:
wait.ForListeningPort(...) for services that only need the socket upwait.ForLog(...) when service logs are the most reliable readiness signalPostgres specifically benefits from explicit readiness checks like postgres.BasicWaitStrategies().
Prefer runtime discovery over fixed ports:
ctr.ConnectionString(ctx, ...) for Postgresctr.ConnectionString(ctx) for Redisctr.Endpoint(ctx, "") or ctr.MappedPort(ctx, ...) for generic containersDo not hardcode localhost:5432 or localhost:6379.
Parallel tests depend on Docker assigning distinct mapped host ports.
In normal tests:
ctr, err := postgres.Run(ctx, "postgres:16-alpine", postgres.BasicWaitStrategies())
testcontainers.CleanupContainer(t, ctr)
require.NoError(t, err)
In TestMain:
testcontainers.TerminateContainer(...) explicitly after m.Run()Register cleanup immediately after startup.
WithReuseByName(...) exists, but it is experimental.
Avoid making reuse your default because it:
Prefer clean startup/teardown unless you have a deliberate local-only optimisation strategy.
When reviewing testcontainers-go usage, check for:
postgres.Run, redis.Run)Run(...) APIs instead of deprecated patternsAvoid these unless there is a strong reason:
FLUSHDBFLUSHALL in a parallel suitelocalhost:5432 or localhost:6379WithSnapshotting(...) on Redis as a test reset mechanismWithReuseByName(...) in CIvar postgresDSN string
func TestMain(m *testing.M) {
ctx := context.Background()
ctr, err := postgres.Run(ctx,
"postgres:16-alpine",
postgres.WithDatabase("app_test"),
postgres.WithUsername("postgres"),
postgres.WithPassword("postgres"),
postgres.BasicWaitStrategies(),
)
if err != nil {
log.Fatal(err)
}
postgresDSN, err = ctr.ConnectionString(ctx, "sslmode=disable")
if err != nil {
log.Fatal(err)
}
code := m.Run()
_ = testcontainers.TerminateContainer(ctr)
os.Exit(code)
}
Then make each parallel test isolate its own transaction, schema, or database.
var redisURI string
func TestMain(m *testing.M) {
ctx := context.Background()
ctr, err := tcredis.Run(ctx, "redis:7")
if err != nil {
log.Fatal(err)
}
redisURI, err = ctr.ConnectionString(ctx)
if err != nil {
log.Fatal(err)
}
code := m.Run()
_ = testcontainers.TerminateContainer(ctr)
os.Exit(code)
}
Then give each parallel test its own logical DB or key prefix.
Source: brpaz/agent-skills — distributed by TomeVault.