-
Notifications
You must be signed in to change notification settings - Fork 328
[testify-expert] Improve Test Quality: pkg/repoutil/repoutil_test.go #24079
Description
The test file pkg/repoutil/repoutil_test.go was selected for quality improvement by the Daily Testify Uber Super Expert. The file uses no testify assertions at all — only the standard testing package — and has a number of actionable improvements available.
Current State
- Test File:
pkg/repoutil/repoutil_test.go - Source File:
pkg/repoutil/repoutil.go(1 exported function:SplitRepoSlug) - Test Functions: 7 test functions + 3 benchmarks
- Lines of Code: 224 lines
- Testify usage: ❌ None — only
"testing"imported
Test Quality Analysis
Strengths ✅
- Good table-driven test structure with descriptive names across most test functions
- Covers a broad range of cases: valid slugs, invalid slugs, special characters, whitespace, idempotency
- Benchmark tests included (
BenchmarkSplitRepoSlug,BenchmarkSplitRepoSlug_Valid,BenchmarkSplitRepoSlug_Invalid)
🎯 Areas for Improvement
1. No Testify Assertions — Replace All Manual Checks
The entire file uses raw t.Errorf / t.Error comparisons instead of testify's require.* and assert.* helpers. This is the single biggest issue.
Current Issues:
// ❌ CURRENT — manual error check, no testify
if tt.expectError {
if err == nil {
t.Errorf("SplitRepoSlug(%q) expected error, got nil", tt.slug)
}
} else {
if err != nil {
t.Errorf("SplitRepoSlug(%q) unexpected error: %v", tt.slug, err)
}
if owner != tt.expectedOwner {
t.Errorf("SplitRepoSlug(%q) owner = %q; want %q", tt.slug, owner, tt.expectedOwner)
}
if repo != tt.expectedRepo {
t.Errorf("SplitRepoSlug(%q) repo = %q; want %q", tt.slug, repo, tt.expectedRepo)
}
}Recommended Changes:
// ✅ IMPROVED — testify with require/assert
if tt.expectError {
require.Error(t, err, "SplitRepoSlug(%q) should return an error", tt.slug)
} else {
require.NoError(t, err, "SplitRepoSlug(%q) should not return an error", tt.slug)
assert.Equal(t, tt.expectedOwner, owner, "owner should match for slug %q", tt.slug)
assert.Equal(t, tt.expectedRepo, repo, "repo should match for slug %q", tt.slug)
}This pattern should be applied consistently to:
TestSplitRepoSlug(the main table-driven test)TestSplitRepoSlug_WhitespaceTestSplitRepoSlug_SpecialCharacters
Why this matters: Testify provides clearer failure output, is the standard used throughout this codebase (see scratchpad/testing.md), and require.* stops the test immediately on critical failures rather than continuing with a potentially broken state.
2. TestSplitRepoSlug_SpecialCharacters — Split the Combined Assertion
The combined owner/repo check loses information when it fails:
// ❌ CURRENT — single Errorf that doesn't tell you which field was wrong
if owner != tt.expectedOwner || repo != tt.expectedRepo {
t.Errorf("SplitRepoSlug(%q) = (%q, %q); want (%q, %q)",
tt.slug, owner, repo, tt.expectedOwner, tt.expectedRepo)
}// ✅ IMPROVED — separate assertions, easier to diagnose failures
require.NoError(t, err, "SplitRepoSlug(%q) should not return an error", tt.slug)
assert.Equal(t, tt.expectedOwner, owner, "owner should match for slug %q", tt.slug)
assert.Equal(t, tt.expectedRepo, repo, "repo should match for slug %q", tt.slug)3. TestSplitRepoSlug_Idempotent — Convert to Testify
The idempotent test uses a raw loop without t.Run and manual t.Error:
// ❌ CURRENT — no t.Run, no testify, continues on error (risky)
for _, slug := range slugs {
owner, repo, err := SplitRepoSlug(slug)
if err != nil {
t.Errorf("Unexpected error for slug %q: %v", slug, err)
continue
}
rejoined := owner + "/" + repo
if rejoined != slug {
t.Errorf("Split and rejoin changed slug: %q -> %q", slug, rejoined)
}
}// ✅ IMPROVED — table-driven with t.Run and testify
func TestSplitRepoSlug_Idempotent(t *testing.T) {
slugs := []string{
"owner/repo",
"github-next/gh-aw",
"my_org/my_repo",
"org123/repo456",
}
for _, slug := range slugs {
t.Run(slug, func(t *testing.T) {
owner, repo, err := SplitRepoSlug(slug)
require.NoError(t, err, "SplitRepoSlug(%q) should succeed", slug)
assert.Equal(t, slug, owner+"/"+repo, "split-and-rejoin should be identity for %q", slug)
})
}
}4. TestSplitRepoSlug_Whitespace — Verify Returned Values
The whitespace tests only check whether an error occurred but never assert what owner and repo contain. Given the comments ("Will split but owner will have space"), the actual returned values should be asserted to document — and enforce — the behaviour:
// ✅ IMPROVED — assert actual values, not just no-error
{
name: "leading whitespace",
slug: " owner/repo",
expectedOwner: " owner",
expectedRepo: "repo",
expectError: false,
},
// ... etc.
// In the test body:
if tt.expectError {
require.Error(t, err, "expected error for slug %q", tt.slug)
} else {
require.NoError(t, err, "unexpected error for slug %q", tt.slug)
assert.Equal(t, tt.expectedOwner, owner)
assert.Equal(t, tt.expectedRepo, repo)
}5. Missing require Import
The file currently only imports "testing". After applying the changes above, the import block should be:
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)📋 Implementation Guidelines
Priority Order
- High: Add testify imports and replace all
t.Errorf/t.Errorwithrequire.*/assert.* - High: Split the combined owner/repo comparison in
TestSplitRepoSlug_SpecialCharacters - Medium: Refactor
TestSplitRepoSlug_Idempotentto uset.Run+ testify - Medium: Add expected-value assertions to
TestSplitRepoSlug_Whitespace
Best Practices from scratchpad/testing.md
- ✅ Use
require.*for critical setup and error-path checks (stops test on failure) - ✅ Use
assert.*for value comparisons (continues checking all fields) - ✅ Write table-driven tests with
t.Run()and descriptive names - ✅ Always include helpful assertion messages
Testing Commands
# Run only this package's tests
go test -v ./pkg/repoutil/
# Run with race detector
go test -race ./pkg/repoutil/
# Run full unit suite before committing
make test-unitAcceptance Criteria
-
"github.com/stretchr/testify/assert"and"github.com/stretchr/testify/require"imported - All
if err == nil { t.Errorf(...) }/if err != nil { t.Errorf(...) }replaced withrequire.Error/require.NoError - All manual value comparisons (
if owner != tt.expectedOwner { t.Errorf(...) }) replaced withassert.Equal -
TestSplitRepoSlug_Idempotentusest.Runand testify assertions -
TestSplitRepoSlug_Whitespaceasserts the returnedowner/repovalues - All assertions include helpful messages
- Tests pass:
go test -v ./pkg/repoutil/ - Code follows patterns in
scratchpad/testing.md
Additional Context
- Repository Testing Guidelines: See
scratchpad/testing.mdfor comprehensive testing patterns - Testify Documentation: https://github.com/stretchr/testify
- Example well-tested file:
pkg/gitutil/gitutil_test.go(same package style, already uses testify correctly)
Priority: Medium
Effort: Small (mostly mechanical replacement)
Expected Impact: Clearer test failure messages, consistent assertion style, easier to extend
Files Involved:
- Test file:
pkg/repoutil/repoutil_test.go - Source file:
pkg/repoutil/repoutil.go
References:
Generated by Daily Testify Uber Super Expert · ◷
- expires on Apr 4, 2026, 11:42 AM UTC