| name | write-go-tests |
| description | Conventions for writing Go tests in the reearth-cms server (server/) — table-driven tests with t.Parallel(), interactor tests using in-memory repositories, and e2e GraphQL tests. Use when adding or fixing tests for pkg/ domain code, internal/usecase/interactor logic, or e2e/ flows, or when a test is flaky, skipped, or won't compile. |
Writing Go tests for the reearth-cms server
Table-driven + parallel (default for everything)
func TestField_Validate(t *testing.T) {
t.Parallel()
tests := []struct {
name string
field *Field
value *value.Value
wantErr bool
}{
{name: "required with value", field: ..., value: ..., wantErr: false},
{name: "required without value", field: ..., value: nil, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
err := tt.field.Validate(tt.value)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
Rules:
t.Parallel() on the parent and each subtest.
- Build fresh test data inside each subtest — no shared mutable state across cases (race detector runs in CI:
go test -race).
- Use
testify: assert for soft checks, require when later lines depend on the result.
Domain tests (pkg/)
Pure, no I/O. Construct via the builder, exercise methods, assert on results and sentinel errors:
g, err := group.New().NewID().Name("x").Build()
assert.ErrorIs(t, err, id.ErrDuplicatedKey)
Interactor tests (internal/usecase/interactor/)
Use in-memory repositories from internal/infrastructure/memory, not mongo. Build a repo.Container, seed it, run the use case, assert:
db := memory.New()
uc := NewGroup(db, nil)
got, err := uc.Create(ctx, interfaces.CreateGroupParam{...}, op)
- Build an
*usecase.Operator with the right workspace/project roles to pass permission checks; test the denied path too (interfaces.ErrOperationDenied).
- Memory repos expose an injectable
err field — set it to test repository-failure branches.
Mocks
mockgen mocks (regenerated by go generate ./...) exist for repo/gateway interfaces. Prefer memory repos for interactor behavior; reach for mocks only to assert specific call sequences.
e2e tests (e2e/)
Full GraphQL flow via httpexpect. Reference e2e/gql_item_test.go and helpers in e2e/common_test.go (StartServer, StartServerWithRepos, seeders).
⚠️ e2e tests require MongoDB. They skip silently in short mode and need the DB env var:
export REEARTH_CMS_DB='mongodb://localhost:27017/test'
make run-db
go test ./e2e/...
Without REEARTH_CMS_DB set, e2e tests skip rather than fail — easy to mistake for passing.
Running
go test ./pkg/myfeature/...
make test
go test -run TestName ./path/...