.claude/skills/review-test/SKILL.md
Review a test PR
npx skillsauth add viqueen/claude-go-playground .claude/skills/review-testInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Audit a test PR. Answer the question: "Is this adequately tested?"
Fetch the PR diff:
gh pr diff <number>
Identify the domain being tested and read the full files (not just the diff).
Identify the project from the PR file paths: connect-rpc-backend/ or grpc-backend/.
Check every item below. For each, report PASS or FAIL with a brief explanation. Items marked (Connect-RPC) or (gRPC) only apply to the corresponding project.
pkg/testkit/containers.goSetupPostgres() starts a postgres container via testcontainers-go/modules/postgresSetupPostgres() runs goose migrations against the containerSetupPostgres() returns a connection stringt.Cleanup() (not defer in test functions)service_test.go or op_*_test.go files (domain tests are redundant — API integration tests cover the full stack)handler_test.go contains only setup (no Test* functions)route_<rpc>_test.go per API routeevent_<concern>_test.gointernal/api/<domain>/v1/handler_test.go defines accessLevel enum: anonymous, standard, admin, elevatedhandler_test.go defines testClients[T] struct with all four client fieldshandler_test.go defines panicService for interceptor-only testssetupHandler(t) — no database, uses panic service (interceptor-level errors)setupHandlerWithDB(t) — testcontainers postgres, real service (domain errors + success)startServer(t, handler) — shared helper creating server + clients (used by both setup functions)anonymous client sends no auth credentialshttptest.NewServer with per-level Connect clientsbufconn with per-level gRPC clientssetupHandlerWithDB uses testcontainers for the database backend (no mocks)route_*_test.go has two parent tests: Test<Endpoint>_Errors + Test<Endpoint>_Success_Errors calls setupHandler(t) at parent level — interceptor errors only (no DB)_Success calls setupHandlerWithDB(t) at parent level — domain errors + success cases (with DB)t.Parallel()clients.anonymous in _Errorsclients.standard → PermissionDenied in _Errorsclients.admin → PermissionDenied in _Errors_Success (they need the DB)connect.CodeUnauthenticated, connect.CodePermissionDenied, connect.CodeNotFound, etc.codes.Unauthenticated, codes.PermissionDenied, codes.NotFound, etc. (via status.Code(err))internal/outbox/<domain>/JobArgs construction from outbox.EventKind() returns correct job type string_Errors: unauthenticated (anonymous) → invalid argument (standard) → permission denied (standard on admin ops)_Success: not found → already exists → success cases (one or more)Test<Endpoint>_Errors and Test<Endpoint>_Success_Errors subtest names: <error code> — <description> (e.g., "unauthenticated — no token")_Success subtest names: descriptive of scenario (e.g., "creates with optional tags", "not found — nonexistent ID")TestCreate1)github.com/stretchr/testify/assert for general assertionsgithub.com/stretchr/testify/require for setup calls that would panic on failurerequire.NoError used after create/setup callsassert used for value comparisons and error code checksif err != nil { t.Fatal() } patterns[]struct{ name string; ... })Test* functions in setup files (handler_test.go)service_test.go or op_*_test.go files (domain tests are redundant)_Errors tests (interceptor-only, must use setupHandler)t.Parallel() in route subtestsORDER BY with a tiebreaker column (e.g., created_at, id)## Test PR Audit — <domain>
### Summary
<one sentence: pass or issues found>
### File Structure
| Expected File | Present | Setup Only | Status |
|---------------|---------|------------|--------|
| handler_test.go | yes | yes | PASS |
| route_create_content_test.go | yes | — | PASS |
| route_delete_content_test.go | yes | — | PASS |
| ... | ... | ... | ... |
### Coverage Matrix
| Operation | _Errors (no DB) | _Success (with DB) | t.Parallel | Status |
|-----------|----------------|-------------------|------------|--------|
| CreateContent | unauth, invalid arg | success (x2) | yes | PASS |
| DeleteContent | unauth, perm denied | not found, success | yes | PASS |
| ... | ... | ... | ... | ... |
### Assertion Usage
| File | require (setup) | assert (checks) | Status |
|------|----------------|-----------------|--------|
| op_create_test.go | yes | yes | PASS |
| ... | ... | ... | ... |
### Issues
<numbered list of FAIL items with details and suggested fixes>
gh pr diff $ARGUMENTSgh pr view $ARGUMENTS --json number,title,body,state,baseRefName,headRefName,urltools
Review a search indexing PR
tools
Review a scaffold PR
tools
Review a proto PR
tools
Review an integration PR