Go Black Box Test Enforcement
Detect Go test files using white box testing (same package name) and propose conversion to black box testing (package foo_test). Creates export_test.go bridge files when internal symbols need external test access.
When to Use
- Creating new test files (enforce black box from the start)
- Reviewing existing test files in a Go project
- User asks to audit or improve test quality
- The golang-pro agent encounters
*_test.gofiles during implementation
Prerequisites
- go.mod exists: Abort if missing.
- Go source files exist: At least one
.gofile and one*_test.gofile to analyze.
Workflow: Detect White Box Tests
Step 1: Classify Test Files with go list
go list already reports the in-package/external split per package, and honours
build constraints. Use it rather than globbing:
go list -f '{{.ImportPath}} {{.Name}} white={{.TestGoFiles}} black={{.XTestGoFiles}}' ./...
| Field | Package clause | Classification |
|---|---|---|
TestGoFiles |
package foo |
White box — candidate for conversion |
XTestGoFiles |
package foo_test |
Black box — already correct |
Two rules when reading the output:
- Drop
export_test.gofrom the white box set. It is a bridge file and belongs to the source package by design, so it is never a conversion candidate. - A package can legitimately hold both. Seeing entries in
TestGoFilesandXTestGoFilesfor the same package is normal, not a defect.
Why not Glob **/*_test.go and read package lines: a test file behind a
constraint like //go:build linux is matched by Glob on any OS but correctly
excluded by go list, so the manual approach both over- and under-reports. go list also names the source package directly, removing the need to read sibling
non-test files to infer it.
Step 2: Check for export_test.go
For each directory containing test files, check whether an export_test.go already exists.
Step 3: Report Findings
Present a summary table:
| File | Package | Classification | export_test.go |
|---|---|---|---|
calc_test.go |
calculator |
White box | No |
math_test.go |
calculator_test |
Black box | N/A |
internal_test.go |
parser |
White box | Yes |
Workflow: Convert White Box to Black Box
For each white box test file identified:
Step 1: Analyze Unexported Symbol Usage
Read the test file and identify references to unexported symbols (lowercase-initial identifiers) from the package under test:
- Unexported functions/methods called directly
- Unexported types used in variable declarations or assertions
- Unexported struct fields accessed directly
- Unexported constants/variables referenced
Step 2: Determine Conversion Strategy
Case A — No unexported symbols used:
- Change
package footopackage foo_test - Add import for the package under test
- Prefix exported symbol references with the package name (e.g.,
Add(1, 2)→calculator.Add(1, 2))
Case B — Unexported symbols used:
- Change
package footopackage foo_testin the test file - Add import for the package under test
- Create or update
export_test.goin the same directory withpackage foo(no_testsuffix) that exports needed internals:
package foo
// Exported for testing in foo_test package.
var (
TestableInternalFunc = internalFunc
TestableInternalVar = internalVar
)
- Update test file to use the exported aliases via the package import
Case C — Heavy internal coupling (>10 unexported references):
- Flag for manual review rather than automatic conversion
- Suggest refactoring the API to export what tests need, or keeping this specific file as white box with a justifying comment
Step 3: Validate
After conversion, run:
go test ./...
go vet ./...
If tests fail, diagnose: missing imports, renamed references, or unexported symbols not yet bridged via export_test.go.
export_test.go Conventions
- File name: Always
export_test.go(Go convention) - Package: Same as the source package (NOT
_testsuffix) — this is what makes it a bridge - Build constraint: None needed — Go includes
export_test.goonly duringgo test - Naming: Prefix exported aliases with
Testableor use the capitalized form of the original name - Comment: Add
// Exported for testing in <pkg>_test package.header comment - Scope: Export only what tests actually need — do not blanket-export all internals
Error Handling
| Condition | Action |
|---|---|
No go.mod found |
Abort: "Not a Go module." |
| No test files found | Report: "No test files found. Nothing to analyze." |
| All tests already black box | Report: "All test files use black box naming. No conversion needed." |
| Test compilation fails after conversion | Diagnose missing imports or unexported references. Attempt fix (max 2 retries). |
go vet fails after conversion |
Display errors and suggest manual review. |