Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when writing Go tests that need test doubles or cover multiple cases - detect the repo's mocking approach (Mockery v3, gomock, hand-written testify mocks, fakes), table-driven cases, testify suites when the repo uses them, and real-Postgres tests for repository adapters
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Table-driven tests and real-Postgres repository-adapter tests are non-negotiable everywhere. How test doubles are produced is not: follow the repository's own convention (rule repo-conventions-win) rather than importing Mockery into a repo that hand-writes testify mocks or uses gomock.
Core principle: multi-case behaviour is a table; a repository adapter test runs against real Postgres, never a mocked driver; mocks exist only at port boundaries.
ls .mockery.y*ml 2>/dev/null
grep -rlE 'Code generated by mockery|go.uber.org/mock' --include='*.go' . | head -3
.mockery.yml or files headed "Code generated by mockery" → Mockery v3: regenerate, don't hand-edit (see below).go.uber.org/mock imports → gomock: regenerate with mockgen per the repo's go:generate directive, don't hand-edit.type mockFoo struct implementing a port → the repo hand-writes testify mocks (or fakes). Follow that style; do not introduce a generator the repo doesn't already have. TaskTrooper's own server does exactly this (server/internal/port/mocks/llm_client.go)..mockery.yml; v3's defaults are Mock<Interface> in mocks_test.go inside the source package, constructor NewMock<Interface>(t) — don't assume a different naming scheme without checking the config.mockery, go generate ./..., or make mocks) — never hand-edit a generated mock.brew install mockery on macOS; the project's own docs say not to go install mockery@latest..mockery.yaml migrates with mockery migrate; don't hand-port the config.expecter API — use the typed EXPECT() methods, not raw On("MethodName", ...) string calls, so a renamed method breaks compilation instead of silently passing.repo := mocks.NewMockTaskRepository(t) // generated constructor, auto-asserts on cleanup
repo.EXPECT().Create(mock.Anything, task).Return(nil).Once()
svc := NewTaskService(repo)
Every function with more than one case is a table. One row = one behavior with a descriptive name.
func TestTaskService_Create(t *testing.T) {
tests := []struct {
name string
title string
setup func(*mockTaskRepository)
wantErr error
}{
{name: "valid title persists",
title: "Report",
setup: func(r *mockTaskRepository) { r.onCreate(nil) }},
{name: "blank title rejected before DB",
title: " ",
setup: func(r *mockTaskRepository) { /* no expectation: repo must NOT be called */ },
wantErr: domain.ErrInvalidTitle},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
repo := newMockTaskRepository(t)
tt.setup(repo)
_, err := NewTaskService(repo).Create(t.Context(), tt.title)
if !errors.Is(err, tt.wantErr) {
t.Fatalf("got %v, want %v", err, tt.wantErr)
}
})
}
}
Cover success, every error path, and edges (empty, not-found, conflict) as rows. A blank-title row that sets NO expectation proves the repo is never touched on invalid input. Use a testify suite (suite.Suite + SetupTest) only where the repo already uses one for shared fixtures — suites don't support t.Parallel(), so don't introduce one into a repo that parallelizes its tests.
A repository adapter test (the thing implementing the port against pgx/database/sql) is never unit-tested against a mocked driver — it proves nothing about the actual SQL. Use the repo's own test-database harness, or testcontainers-go modules/postgres with the repo's migrations applied, and assert on rows actually read back.
t.Context() (Go ≥1.24) instead of context.Background() in tests — it's canceled on test cleanup.testing/synctest (Go ≥1.25) for deterministic tests of timers, timeouts and goroutine scheduling instead of real time.Sleep.go test -race -count=1 ./... for anything touching concurrency — run it, don't just suggest it..Once()/.Times(n) (or the gomock/hand-written equivalent) only where the count is the behavior under test..On("Create", ...) string calls on a v3 expecter-generated mock.if-branches per case → make it a table.type mock... struct hand-written in a repo whose other tests use a generator.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.