Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
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
The English summary is being prepared. Showing the original description.
Review the instructions the agent will receive before you install.
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.No reviews yet. Tell others what you thought.
No login needed. Share how it worked for you, ask a question, or note where it did not run.
No comments yet. Be the first to write one.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
The English summary is being prepared. Showing the original description.
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
The English summary is being prepared. Showing the original description.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
The English summary is being prepared. Showing the original description.
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
The English summary is being prepared. Showing the original description.
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.
The English summary is being prepared. Showing the original description.
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
The English summary is being prepared. Showing the original description.