🎯 Areas for Improvement
1. Replace All Raw Assertions with Testify
Current Issue: The entire file uses t.Fatalf, t.Fatal, t.Error, and t.Errorf (106 occurrences). Not a single require.* or assert.* call exists. This diverges from the codebase standard.
Examples:
// ❌ CURRENT — verbose and inconsistent
err := os.Chdir(tmpDir)
if err != nil {
t.Fatalf("Failed to change to temp directory: %v", err)
}
// ...
if got != tt.expected {
t.Errorf("extractHostFromRemoteURL(%q) = %q, want %q", tt.url, got, tt.expected)
}
// ...
if branch == "" {
t.Error("getCurrentBranch() returned empty branch name")
}
// ✅ IMPROVED — testify equivalents
err := os.Chdir(tmpDir)
require.NoError(t, err, "should change to temp directory")
// ...
assert.Equal(t, tt.expected, got, "extractHostFromRemoteURL(%q)", tt.url)
// ...
assert.NotEmpty(t, branch, "getCurrentBranch() should return a branch name")
Required import addition:
import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
2. Use require.* for Setup, assert.* for Validations
Current Issue: All failures use t.Fatalf indiscriminately. The distinction between "setup must succeed" vs "this is the assertion" is lost.
Pattern to apply:
- Use
require.* for os.Getwd, os.Chdir, os.WriteFile, git setup — these are preconditions and a failure should stop the test immediately
- Use
assert.* for the actual test assertions (checking return values, booleans, strings)
// ✅ CORRECT distinction
originalDir, err := os.Getwd()
require.NoError(t, err, "should get current directory") // setup
branch, err := getCurrentBranch()
require.NoError(t, err, "getCurrentBranch() should succeed") // setup
assert.NotEmpty(t, branch, "should return a branch name") // assertion
assert.Contains(t, []string{"main", "master"}, branch, "should be on main or master") // assertion
3. Convert In-Table Assertions to Testify
Current Issue: Table-driven tests still use t.Errorf inside t.Run:
// ❌ CURRENT
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractHostFromRemoteURL(tt.url)
if got != tt.expected {
t.Errorf("extractHostFromRemoteURL(%q) = %q, want %q", tt.url, got, tt.expected)
}
})
}
// ✅ IMPROVED — cleaner and self-documenting
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractHostFromRemoteURL(tt.url)
assert.Equal(t, tt.expected, got, "extractHostFromRemoteURL(%q)", tt.url)
})
}
4. Replace Struct-Field Boolean Assertions
Current Issue: Multi-condition boolean checks are verbose and unclear which field failed:
// ❌ CURRENT — hard to diagnose on failure
if status.IsModified || status.IsStaged || status.HasUnpushedCommits {
t.Error("Expected empty status for untracked file")
}
// ✅ IMPROVED — separate assertions give precise failure messages
assert.False(t, status.IsModified, "IsModified should be false for untracked file")
assert.False(t, status.IsStaged, "IsStaged should be false for untracked file")
assert.False(t, status.HasUnpushedCommits, "HasUnpushedCommits should be false for untracked file")
5. Simplify Setup Code with Helpers
Current Issue: Every git-operation test has 20+ lines of boilerplate for creating a temp repo. This is duplicated across TestGetCurrentBranch, TestCreateAndSwitchBranch, TestSwitchBranch, TestCommitChanges, etc.
Recommended: Extract a setupTestRepo helper:
// setupTestRepo creates a temporary git repository and returns the cleanup function.
// Callers should defer the returned cleanup.
func setupTestRepo(t *testing.T) (dir string, cleanup func()) {
t.Helper()
tmpDir := testutil.TempDir(t, "test-git-*")
originalDir, err := os.Getwd()
require.NoError(t, err, "should get current directory")
require.NoError(t, os.Chdir(tmpDir), "should change to temp directory")
if err := exec.Command("git", "init").Run(); err != nil {
t.Skip("Git not available")
}
exec.Command("git", "config", "user.name", "Test User").Run()
exec.Command("git", "config", "user.email", "test@example.com").Run()
// Create initial commit
require.NoError(t, os.WriteFile("init.txt", []byte("init"), 0644))
exec.Command("git", "add", "init.txt").Run()
if err := exec.Command("git", "commit", "-m", "Initial commit").Run(); err != nil {
t.Skip("Failed to create initial commit")
}
return tmpDir, func() { _ = os.Chdir(originalDir) }
}
This would reduce each test by ~25 lines of boilerplate.
Overview
The test file
pkg/cli/git_test.go(904 lines, 14 test functions) was selected for quality improvement. It tests Git-related utilities in the CLI package. While the file has solid test coverage and uses table-driven tests in some places, it entirely avoids testify assertions — relying on rawt.Fatal,t.Error, andt.Errorfthroughout. Migrating to testify would improve test clarity, reduce verbosity, and align with the codebase standard described inscratchpad/testing.md.Current State
pkg/cli/git_test.gopkg/cli/git.gorequire.*/assert.*callsTest Quality Analysis
Strengths ✅
t.Run()for pure functions (e.g.,TestExtractHostFromRemoteURL,TestResolveRemoteURL)testutil.TempDirand directory restoration viadefer🎯 Areas for Improvement
1. Replace All Raw Assertions with Testify
Current Issue: The entire file uses
t.Fatalf,t.Fatal,t.Error, andt.Errorf(106 occurrences). Not a singlerequire.*orassert.*call exists. This diverges from the codebase standard.Examples:
Required import addition:
2. Use
require.*for Setup,assert.*for ValidationsCurrent Issue: All failures use
t.Fatalfindiscriminately. The distinction between "setup must succeed" vs "this is the assertion" is lost.Pattern to apply:
require.*foros.Getwd,os.Chdir,os.WriteFile, git setup — these are preconditions and a failure should stop the test immediatelyassert.*for the actual test assertions (checking return values, booleans, strings)3. Convert In-Table Assertions to Testify
Current Issue: Table-driven tests still use
t.Errorfinsidet.Run:4. Replace Struct-Field Boolean Assertions
Current Issue: Multi-condition boolean checks are verbose and unclear which field failed:
5. Simplify Setup Code with Helpers
Current Issue: Every git-operation test has 20+ lines of boilerplate for creating a temp repo. This is duplicated across
TestGetCurrentBranch,TestCreateAndSwitchBranch,TestSwitchBranch,TestCommitChanges, etc.Recommended: Extract a
setupTestRepohelper:This would reduce each test by ~25 lines of boilerplate.
📋 Implementation Guidelines
Priority Order
requireandassertimports; replacet.Fatalf/t.Error/t.Errorfwith testify equivalentsassert.False/assert.TruecallssetupTestRepohelper to reduce duplicationTesting Commands
Best Practices Reminder (from
scratchpad/testing.md)require.*for critical setup (stops test on failure)assert.*for test validations (continues checking)Acceptance Criteria
requireandassertpackages imported fromgithub.com/stretchr/testifyt.Fatalf(...)in setup code replaced withrequire.NoError(t, err, "...")t.Error(...)/t.Errorf(...)in assertion code replaced withassert.*setupTestRepohelper extracted to reduce boilerplatego test -v ./pkg/cli/ -run "TestGetCurrentBranch|TestCreateAndSwitch|TestSwitchBranch|TestCommitChanges|TestCheckWorkflowFileStatus|TestExtractHost|TestGetHost|TestResolveRemote|TestGetRepositorySlug"scratchpad/testing.mdAdditional Context
scratchpad/testing.mdpkg/stringutil/stringutil_test.go,pkg/cli/compile_args_test.goPriority: Medium
Effort: Medium (mechanical replacement, ~904 lines)
Expected Impact: Cleaner test output, better failure messages, alignment with codebase standards
Files Involved:
pkg/cli/git_test.gopkg/cli/git.goReferences: