Skip to content

Conversation

@newhook
Copy link
Owner

@newhook newhook commented Jan 30, 2026

Summary

This PR standardizes test mocking across the codebase by adopting moq for mock generation. It replaces hand-coded mocks and testify/mock-based mocks with a unified moq-generated approach, and modernizes all tests to use testify assertions.

Key improvements:

  • Set up moq infrastructure with mise run generate task for regenerating mocks
  • Generated mocks live in their respective package directories (co-located with source)
  • Converted all test files to use testify assertions (require/assert), removing ~700 lines of verbose error handling
  • Added comprehensive test coverage for previously untested packages
  • Fixed linter warnings (gosec, unparam) in test files

Changes

Infrastructure

  • Added moq tool to mise.toml (go:github.com/matryer/moq)
  • Added mise run generate task for go generate ./...
  • Removed centralized internal/testutil/ package—mocks now live alongside their interfaces

Generated Mocks (13 interfaces)

Mocks are co-located with their interfaces in each package:

Package Interface Mock File
beads CLI, Reader beads_mock.go
claude Runner claude_mock.go
feedback Processor feedback_mock.go
git Operations git_mock.go
github ClientInterface github_mock.go
linear Client linear_mock.go
mise Operations mise_mock.go
process Lister, Killer process_mock.go
task ComplexityEstimator task_mock.go
worktree Operations worktree_mock.go
zellij SessionManager, Session zellij_mock.go

Test Modernization

  • Testify assertions: Converted all 19 test files to use require/assert instead of manual if err != nil checks
  • Cleaner test setup: Refactored setupControlPlane helper to return a struct instead of multiple values
  • Removed dead code: Deleted empty tests that only contained documentation comments
  • Linter compliance: Fixed gosec (G115) and unparam warnings in test files

Converted Tests

  • internal/beads/cachemanager/ - Removed testify/mock dependency
  • internal/process/ - Converted hand-coded mocks
  • internal/task/planner_test.go - Converted hand-coded mocks
  • internal/linear/fetcher_test.go - Converted function-field mocks
  • internal/work/import_pr_test.go - Consolidated local mocks into package mocks

New Test Coverage

  • internal/git/git_test.go - Tests for git operations
  • internal/worktree/worktree_test.go - Tests for worktree operations
  • internal/mise/mise_test.go - Tests for mise tool management
  • internal/beads/client_test.go - Tests for beads client caching
  • internal/control/control_test.go - Comprehensive control plane tests

Beads Resolved

  • ac-t4vk: Adopt moq for test mock generation (epic)
  • ac-t4vk.1: Set up moq infrastructure and shared testutil package
  • ac-t4vk.2: Generate mocks for CLI wrapper interfaces
  • ac-t4vk.3: Convert cachemanager tests from testify/mock to moq
  • ac-t4vk.4: Convert process tests to use moq-generated mocks
  • ac-t4vk.5: Convert task/planner tests to use moq-generated mocks
  • ac-t4vk.6: Convert linear/fetcher tests to use moq-generated mocks
  • ac-t4vk.7: Consolidate work/import_pr mocks into shared testutil
  • ac-t4vk.8: Update CLAUDE.md with mock generation documentation
  • ac-t4vk.9: Add tests for control plane using moq mocks
  • ac-t4vk.10: Add tests for git package using moq mocks
  • ac-t4vk.11: Add tests for worktree package using moq mocks
  • ac-t4vk.12: Add tests for mise package using moq mocks
  • ac-t4vk.13: Add tests for beads client caching logic

Stats

53 files changed, 7370 insertions(+), 1366 deletions(-)

Net effect: ~6000 lines added (mostly new tests and generated mocks)

Test Plan

  • All existing tests pass (go test ./...)
  • New tests added for previously untested packages
  • Mocks regenerate cleanly with mise run generate
  • No linter warnings (golangci-lint run)

Usage

To regenerate mocks after interface changes:

mise run generate

To add a new mock, add a //go:generate directive to the interface file:

//go:generate moq -stub -out mypkg_mock.go . InterfaceName:InterfaceNameMock

🤖 Generated with Claude Code

newhook and others added 14 commits January 30, 2026 00:08
- Add moq to mise.toml tools
- Create internal/testutil/ package with documentation
- Add mise generate task for running go generate
- Document mock generation workflow in CLAUDE.md

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add go:generate directives and generate mocks for:
- git.Operations (GitOperationsMock)
- worktree.Operations (WorktreeOperationsMock)
- mise.Operations (MiseOperationsMock)
- zellij.SessionManager and Session
- beads.CLI (BeadsCLIMock) and Reader (BeadsReaderMock)
- github.ClientInterface (GitHubClientMock)
- claude.Runner (ClaudeRunnerMock)
- process.ProcessLister and ProcessKiller
- task.ComplexityEstimator
- linear.ClientInterface (LinearClientMock)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace testify/mock embedding with function-field pattern
consistent with moq-generated mocks. Hand-written since moq
doesn't support generic interfaces.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace hand-coded mockProcessLister and mockProcessKiller with
moq-generated ProcessListerMock and ProcessKillerMock from testutil.

Use external test package (process_test) to avoid import cycles
between process and testutil. Move escapePattern test to internal
test file since it tests an unexported function.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Split tests into external test package (planner_test.go) using
testutil.ComplexityEstimatorMock, and internal test file (internal_test.go)
for testing unexported functions like canAddToTask and ComputeInterTaskDeps.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace incomplete MockClient with LinearClientMock that implements full
ClientInterface using function-field pattern. Kept tests in internal package
due to import cycle (testutil imports linear). Mock is hand-written in same
style as moq-generated mocks, consistent with cachemanager approach.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove duplicate MockClientInterface, MockGitOperations, MockWorktreeOperations
- Use moq-generated GitHubClientMock, GitOperationsMock, WorktreeOperationsMock
- All tests continue to pass using shared mocks

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Test NewOperations returns valid implementation
- Verify GitOperationsMock implements git.Operations interface
- Test mock function field behavior for BranchExists, ValidateExistingBranch
- Test mock call tracking for FetchPRRef, PushSetUpstream, Pull, Clone
- Test nil function returns zero values

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Test parseWorktreeList parsing: empty, single, multiple worktrees
- Test edge cases: detached HEAD, paths with spaces, branch slashes
- Test mock interface compliance with worktree.Operations
- Test mock function field behavior and call argument tracking
- Split into internal (worktree_test.go) and external (mock_test.go) tests

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Test findConfigFile detection for all config file variants
- Test config file priority order (.mise.toml before mise.toml etc)
- Test IsManaged detection at both package and Operations level
- Test mock interface compliance with mise.Operations
- Test mock function field behavior for all methods
- Test mock call tracking for HasTask, RunTask, Exec arguments

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Move CacheManagerMock from _test.go to exportable file
- Test CacheManagerMock Get/Set/Flush behavior with function fields
- Test cache hit/miss scenarios with BeadsWithDepsResult type
- Test FlushCache handles nil cache gracefully
- Test BeadsWithDepsResult.GetBead for existing and non-existing beads
- Test DefaultClientConfig returns expected defaults
- Document cache key generation behavior (sorted IDs joined by comma)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Add installation instructions for moq via mise and comprehensive testing
best practices section including call tracking, nil function behavior,
and compile-time interface verification examples.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Generate mocks for OrchestratorSpawner, WorkDestroyer interfaces
- Generate mock for feedback.Processor interface
- Add comprehensive tests for control plane handlers:
  - HandleGitPushTask (93.8% coverage)
  - HandleSpawnOrchestratorTask (93.3% coverage)
  - HandleDestroyWorktreeTask (91.7% coverage)
  - HandlePRFeedbackTask (90% coverage)
  - HandleCreateWorktreeTask (partial)
- Add tests for scheduler functions
- Add tests for ProcessAllDueTasksWithControlPlane
- Add tests for HandleTaskError
- Control mocks kept local to avoid import cycle with work package
- Update CLAUDE.md with new mock documentation

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Change directory permissions from 0755 to 0750 in mise_test.go (G301)
- Remove unused MiseOperationsMock return value from setupControlPlane

Co-Authored-By: Claude Opus 4.5 <[email protected]>
newhook and others added 5 commits January 30, 2026 08:14
Replace manual if/t.Error patterns with testify/require assertions
across 19 test files for more readable and consistent test code:

- require.NoError for error checks
- require.Equal for value comparisons
- require.True/False for boolean checks
- require.Nil/NotNil for nil checks
- require.Len for length checks
- require.Contains for substring checks
- require.NotPanics for panic-safe code paths

Closes bead ac-t4vk.16

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Instead of generating mocks in a central internal/testutil/ package,
mocks are now generated in their respective package directories
(e.g., git_mock.go in internal/git/). This makes mocks easier to find
and follows Go conventions of keeping related code together.

Changes:
- Update all //go:generate directives to output mocks locally
- Update all test files to import mocks from their packages
- Remove internal/testutil/ package (now empty)
- Update CLAUDE.md documentation with new mock locations

Co-Authored-By: Claude Opus 4.5 <[email protected]>
These tests were testing the moq library itself rather than project code.
The mock behavior is already tested by moq's maintainers.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@newhook newhook merged commit 2af41d5 into main Jan 30, 2026
3 checks passed
@newhook newhook deleted the feat/adopt-moq-for-test-mock-generation branch January 30, 2026 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants