OpenAPI v3 Generator Testing Guide
This document describes the comprehensive testing strategy for the protoc-gen-openapiv3 plugin.
Testing Architecture#
The OpenAPI v3 generator uses a multi-tier testing approach to ensure correctness, reliability, and regression detection:
1. Unit Tests (*_test.go)#
- Purpose: Test individual components and functions in isolation
- Scope: Core generator functions, type mapping, schema building
- Files:
generator_test.go- Core generator functionalitytypes_test.go- Type system and protobuf-to-OpenAPI mappingvalidation_test.go- Validation rule processinghttp_annotations_test.go- HTTP annotation parsing
2. Golden File Tests (exhaustive_golden_test.go)#
- Purpose: Exhaustive regression detection via byte-for-byte comparison
- Scope: Complete plugin execution through protoc
- Benefits:
- Catches ANY change in generated output
- Tests real protoc execution (not mocked)
- Ensures consistency across formats (YAML/JSON)
3. Integration Tests (integration_test.go)#
- Purpose: End-to-end plugin integration with protoc
- Scope: Plugin invocation, error handling, format options
- Coverage:
- Multiple proto file scenarios
- Format option validation
- Error condition handling
- Service generation verification
Test Data Organization#
internal/openapiv3/testdata/
├── proto/ # Input proto files
│ ├── simple_service.proto # Basic service with standard messages
│ ├── multiple_services.proto # Multiple services in one file
│ ├── complex_types.proto # Complex message types (optional fields)
│ ├── nested_messages.proto # Nested message structures
│ ├── headers.proto # Header validation configurations
│ ├── validation_constraints.proto # buf.validate integration
│ ├── http_annotations.proto # HTTP method annotations
│ └── no_services.proto # Edge case: no services defined
└── golden/ # Expected output files
├── yaml/ # YAML format golden files
│ ├── SimpleService.openapi.yaml
│ ├── UserService.openapi.yaml
│ └── ...
└── json/ # JSON format golden files
├── SimpleService.openapi.json
├── UserService.openapi.json
└── ...
Running Tests#
All Tests#
# Run complete test suite
go test -v ./internal/openapiv3/...
# Run with coverage analysis
go test -v -coverprofile=coverage.out ./internal/openapiv3/...
go tool cover -html=coverage.outSpecific Test Categories#
Unit Tests Only#
# Fast unit tests
go test -v -run "^Test[^E]" ./internal/openapiv3/Golden File Tests Only#
# Comprehensive regression tests
go test -v -run TestExhaustiveGoldenFiles ./internal/openapiv3/Integration Tests Only#
# Plugin integration tests
go test -v -run TestPlugin ./internal/openapiv3/Golden File Management#
Updating Golden Files#
When intentional changes are made to the generator output:
# Update all golden files
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles ./internal/openapiv3/
# Or use the generation script
./scripts/generate_openapi_golden_files.shAdding New Test Cases#
- Create new proto file in
testdata/proto/ - Add test case to
exhaustive_golden_test.go - Generate golden files:
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles ./internal/openapiv3/ - Verify generated files are correct
- Commit both proto file and golden files
Test Coverage Goals#
- Unit Tests: >90% line coverage
- Golden Files: 100% of supported proto patterns
- Integration: All major plugin features and error paths
- Regression: Detect any change in output format
Common Test Patterns#
Testing New Features#
-
Add Unit Test: Test the feature logic in isolation
func TestNewFeature(t *testing.T) { // Test the specific function/method } -
Add Proto Test Case: Create proto file exercising the feature
service TestService { rpc TestMethod(Request) returns (Response) { // Feature-specific annotations }; } -
Generate Golden File: Let the generator create expected output
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles -
Verify Integration: Ensure feature works end-to-end
func TestNewFeatureIntegration(t *testing.T) { // Test via protoc execution }
Testing Error Conditions#
func TestErrorHandling(t *testing.T) {
testCases := []struct {
name string
input string
expectError bool
errorMsg string
}{
// Test cases for various error conditions
}
// ... test implementation
}Testing Format Variations#
func TestFormats(t *testing.T) {
formats := []string{"yaml", "json"}
for _, format := range formats {
t.Run(format, func(t *testing.T) {
// Test both YAML and JSON output
})
}
}Debugging Test Failures#
Golden File Mismatches#
When golden file tests fail:
- Check diff output: Test failure shows first differences
- Compare files: Use generated
.generatedfilediff testdata/golden/yaml/service.openapi.yaml testdata/golden/yaml/service.openapi.yaml.generated - Verify changes: Ensure changes are intentional
- Update if needed:
UPDATE_GOLDEN=1 go test -run TestExhaustiveGoldenFiles
Integration Test Failures#
When integration tests fail:
- Check protoc output: Look at command execution details
- Verify plugin build: Ensure plugin compiles correctly
- Test manually: Run protoc command directly
protoc --plugin=protoc-gen-openapiv3=./plugin \ --openapiv3_out=./output \ --proto_path=./proto \ service.proto
Test Performance#
Benchmark Tests#
func BenchmarkGeneration(b *testing.B) {
// Benchmark critical paths
}Test Optimization#
- Parallel execution: Use
t.Parallel()where appropriate - Shared setup: Reuse plugin builds across tests
- Targeted tests: Run specific test categories during development
Continuous Integration#
Tests run automatically on:
- Pull requests: Full test suite + coverage analysis
- Main branch: Full test suite + regression detection
- Releases: Extended test suite + golden file validation
CI Configuration#
- Minimum coverage threshold: 85%
- Golden file validation required
- Integration tests must pass
- No test skips allowed in CI
Best Practices#
- Test Independence: Each test should be self-contained
- Clear Naming: Test names should describe what they verify
- Comprehensive Coverage: Test both success and failure paths
- Maintainable Assertions: Use helper functions for complex validations
- Documentation: Comment complex test logic
- Fast Execution: Keep unit tests fast, use integration tests for E2E
Troubleshooting#
Common Issues#
- Import path errors: Verify proto_path settings
- Plugin not found: Check plugin build and path
- Golden file encoding: Ensure consistent line endings
- Protoc version: Use compatible protoc version
Getting Help#
- Check existing test patterns
- Review CLAUDE.md for project conventions
- Look at similar tests in other generators (oneofhelper, httpgen)
- Create minimal reproduction case
