Ratio (test files / source files): ~0.28 (1 test file per 3.5 source files)
Test frameworks:github.com/stretchr/testify/require + testify/assert (stdlib testing as foundation); github.com/charmbracelet/x/exp/golden for UI snapshot tests; charm.land/x/vcr for HTTP cassette recording/replay in agent integration tests
Placement: Same package throughout — all 79 test files declare the same package name as the production code (package agent, package config, etc.), with the sole exception of internal/ui/diffview/diffview_test.go which uses package diffview_test (external black-box test for the UI component)
Helper packages:
No dedicated testutil/ package; helpers live alongside the tests they support
internal/agent/common_test.go — fakeEnv struct + factory functions (testEnv, testSessionAgent, coderAgent) that construct a full in-process environment (SQLite DB, real service implementations, VCR-wrapped HTTP client) for agent integration tests
internal/config/store.go:NewTestStore — a production-code helper exported specifically to simplify config setup in tests across packages. Rare to see this pattern; it keeps test setup DRY without a separate test helper package.
internal/lsp/client_test.go:newTestClient — constructs a minimal LSP client wired to an in-process stdio pipe for protocol-level testing
Fixtures:
internal/agent/testdata/ — VCR cassette directories (TestCoderAgent/) containing recorded HTTP interactions with the LLM API backend; replayed on go test runs without live network calls
internal/agent/tools/testdata/grep.txt — a real-file fixture for the grep tool’s content search tests
internal/ui/diffview/testdata/ — before/after diff pairs (TestDefault.before, TestDefault.after, etc.) embedded via //go:embed for diffview rendering tests; golden output files generated by github.com/charmbracelet/x/exp/golden (auto-updated with -update flag)
Prevalence: Heavy — 43 occurrences of table-struct / t.Run / testCases / tc.name patterns in test files; this is the default test style throughout the codebase
Style: Anonymous struct slice ([]struct{ name string; ... }) iterated with t.Run(tt.name, func(t *testing.T) { ... }). Named variants appear in some packages (e.g., testCases map in shell tests).
Example:internal/permission/permission_test.go:11 — 5-case table for TestPermissionService_AllowedCommands covering all combinations of tool, tool:action, and missing allowlist entries. Each case runs in isolation as a subtest.
Prevalence: Very heavy — 376 calls to t.Parallel() across test files; nearly every top-level test and most subtests call t.Parallel() explicitly
Pattern: Called immediately inside t.Run(...) closures, consistent with Go’s recommended style for safe parallelism. Tests are designed with no shared mutable state, using t.TempDir() and t.Context() for isolation.
Example:internal/app/app_test.go:16 — TestSetupSubscriber_NormalFlow calls t.Parallel() at line 1 and uses context derived from t.Context() so the test is automatically cancelled when the test finishes.
Strategy: Manual interface implementations (hand-rolled fakes) — no gomock, mockery, or other generation tools
Example 1 — mockSessionAgent (internal/agent/coordinator_test.go:16): A struct implementing the full SessionAgent interface with exported function fields (runFunc, cancelled []string) that tests configure per-case. Methods like Cancel() record calls so tests can assert behavior.
Example 2 — Direct production type (internal/permission/permission_test.go:68): For simple cases, the test accesses the concrete permissionService struct directly to read internal state (ps.allowedTools), bypassing the interface. Used when behavioral verification of internals is needed.
Example 3 — Real services over fakes: internal/agent/common_test.go:testEnv() constructs real session.Service, message.Service, history.Service, and filetracker.Service instances backed by a real SQLite database in t.TempDir(). No fakes for the data layer — they use the real thing.
Framework:charm.land/x/vcr — a Charmbracelet-internal HTTP cassette recorder/replayer
Mechanism:*vcr.Recorder wraps the HTTP transport passed to the LLM provider (openaicompat.WithHTTPClient). On first run (with a live API key in CRUSH_HYPER_API_KEY), responses are recorded to testdata/<TestName>/ cassette files. On subsequent runs, the recorder replays from cassettes — no live network calls needed.
Purpose: Allows full end-to-end testing of the agent loop (tool calls, multi-turn conversations, coder agent behaviour) without paying per-test API costs or flakiness from LLM non-determinism. This is the only viable pattern for deterministic AI agent testing.
Location:internal/agent/agent_test.go — TestCoderAgent and related agent loop tests; internal/agent/coordinator_test.go — coordinator round-trip tests
Comparison: Similar to go-vcr or Ruby’s VCR gem; more principled than nondeterministic live tests or over-mocked unit tests.
Mechanism:golden.RequireEqual(t, []byte(output)) writes rendered output to testdata/<TestName>.golden on first run (or with -update flag) and asserts byte equality on subsequent runs
Usage:internal/ui/diffview/diffview_test.go — renders the DiffView component at various sizes (width, height, x-offset, y-offset) and both unified/split modes, then compares against stored golden snapshots; internal/ui/diffview/udiff_test.go — golden snapshots for raw unified-diff string output
Value: Catches regressions in terminal rendering (ANSI escape sequences, line wrapping, color themes) that are nearly impossible to assert with manual expected strings
Notable: The csync/maps_test.go benchmarks are thorough — they test concurrent read/write under b.RunParallel to catch mutex contention. The regex cache benchmark (tools/grep_test.go:179) validates the decision to cache compiled regexps vs. recompiling on each call.
Present: Yes (agent VCR tests are effectively integration tests)
How: In-process, using real SQLite (via t.TempDir()), real service implementations, and HTTP cassette replay for the LLM backend. No Docker or testcontainers.
Separation: No separate _integration_test.go naming convention or build tags — integration tests live alongside unit tests in the same file. The presence of charm.land/x/vcr import and a *vcr.Recorder argument is the de facto marker.
Note: CI runs all tests on all platforms with -race, meaning agent integration tests (via cassette replay) are part of the standard go test suite with no separate gate.
t.Parallel() discipline is exemplary: 376 parallel calls means near-zero idle time in the test suite. Combined with t.TempDir() and t.Context() for isolation, tests are both fast and safe.
VCR cassette replay for agents: Recording real LLM interactions and replaying them deterministically is architecturally necessary for an AI coding assistant. The team solved the hardest testing problem in the project — deterministic agent behavior — without sacrificing realism.
Real data layer in tests: Using a real SQLite database (via t.TempDir()) rather than faking session.Service means the agent loop tests catch real data-layer bugs. The trade-off (slightly slower setup) is worth it for a system where DB schema and ORM query correctness are critical.
Golden files for TUI: Catching ANSI rendering regressions with golden snapshots is the right call for a terminal UI. Manual assertions over escape codes would be brittle and unreadable.
Benchmark coverage of the csync library: The generic concurrent collections in internal/csync are used throughout the hot path. Benchmarking Map.Set/Get/Seq2 under concurrent load proves correctness under contention and establishes a performance baseline.
TestMain for test-global setup:config/load_test.go calls slog.SetDefault(slog.New(slog.NewTextHandler(io.Discard, nil))) in TestMain to silence log noise during test runs — a small but professional touch.
Race detector always on: CI runs go test -race -failfast ./... on Ubuntu, macOS, and Windows. Catching data races in a heavily concurrent codebase on all platforms before merge is a strong safety net.
No build tag separation for cassette-dependent tests: Tests that require cassette files (or a live CRUSH_HYPER_API_KEY to regenerate them) run unconditionally in go test ./.... If cassettes are stale or missing for a new test, the test silently depends on a live API or fails non-obviously. A //go:build integration or //go:build vcr tag on agent integration tests would make this dependency explicit.
Allowlist test accesses private struct directly (permission_test.go:68): Testing ps.allowedTools via type assertion to the concrete permissionService couples the test to the implementation. Exposing an IsAllowed(toolName, action string) bool method would let the test remain at the interface boundary.
No test coverage reporting: The CI build.yml runs go test without -cover or coverage upload. For a project of this complexity, even a basic Codecov integration would help identify under-tested packages.
Minimal TUI model tests:internal/ui/model/ui_test.go and internal/ui/model/layout_test.go exist but are likely thin given the complexity of the BubbleTea Update loop. The TUI is the hardest part to test (inherently I/O-bound, stateful), but more coverage of the Update dispatch logic would reduce regression risk.
VCR cassette replay for AI/LLM integration tests — essential pattern for any project interacting with non-deterministic external APIs. Record once, replay forever, CI stays green.
t.Parallel() by default everywhere — the project demonstrates that a heavily concurrent codebase can have a fast, fully parallel test suite with zero shared mutable state. Achieved by t.TempDir() + t.Context() per test.
Production-exported test helper (config.NewTestStore) — a pragmatic alternative to a separate testutil package when the helper is tightly coupled to a single type’s internals. Keeps test setup DRY without a dependency cycle.
Benchmarks for generic concurrency primitives — when you write a lock-protected generic collection used throughout the hot path, benchmark it. The csync benchmarks act as both correctness proofs and regression guards for the most critical shared data structures.