Guides
Testing Documentation
Overview
This document outlines the testing strategy, patterns, and technical decisions for the Arches backend.
Testing Philosophy
- Minimal Dependencies: Tests use Go's standard library with minimal external dependencies
- Mock Repository Pattern: All database interactions are mocked using in-memory implementations
- Table-Driven Tests: Comprehensive test cases using Go's table-driven test pattern
- Domain Isolation: Each domain is tested independently without cross-domain dependencies
Technical Decisions
1. Mock Repository Pattern
We use mockery v3 to generate mocks from interfaces. The unified code generator creates repository interfaces that mockery then uses to generate test mocks.
Code
Benefits:
- Automatic generation from generated interfaces
- Consistent mock patterns across all domains
- Type-safe mocks matching repository contracts
- Integration with testify assertions
2. Test Organization
Each domain follows this structure:
Code
3. Integration Testing
For database integration tests, we use testcontainers:
- PostgreSQL containers for testing real database operations
- Redis containers for testing cache operations
- Automatic cleanup after tests complete
- Located in
internal/testutil/containers.go
4. Coverage Strategy
Current coverage by package:
internal/auth
- 20.2%internal/sessions
- 27.2%internal/infrastructure/config
- 47.2%internal/artifacts
- 17.2%internal/labels
- 16.3%internal/pipelines
- 12.8%internal/users
- 12.2%internal/runs
- 6.4%internal/health
- 3.9%internal/organizations
- 3.3%internal/tools
- 0.0%internal/accounts
- 0.0%internal/invitations
- 0.0%internal/members
- 0.0%
Target: 80%+ coverage for critical business logic
Test Patterns
Service Tests
Code
Handler Tests
Code
Integration Tests
Code
Running Tests
Code
Important Notes
Type Compatibility
-
OpenAPI Generated Types: Always use the exact generated types from
types.gen.go
:Email
field isopenapi_types.Email
, notstring
- Role enums use specific constants like
CreateMemberJSONBodyRoleAdmin
- Request/Response types use generated structs
-
UUID Handling:
- User
ID
field isuuid.UUID
, notID
- Some fields like
OrganizationID
may be strings in certain contexts
- User
-
Context Keys:
- Auth middleware uses
AuthUserContextKey
andAuthClaimsContextKey
- Not
UserContextKey
orClaimsContextKey
- Auth middleware uses
Mock Generation Checklist
When creating mocks for testing:
- Never create manual mocks - always use mockery
- Define interfaces first, then generate mocks
- Run
make generate-mocks
after interface changes - Use generated mocks in
mocks_test.go
files - Mock files follow pattern
Mock{InterfaceName}
Common Pitfalls
- Forgetting Generated Types: Always check
types.gen.go
for correct field types - Missing Interface Methods: Use
var _ Interface = (*Mock)(nil)
to verify - Incorrect Error Variables: Use domain-specific errors like
ErrUserNotFound
- Linting Issues: Run
make lint
before committing - Format Issues: Run
gofmt -w
on test files
Test Data Fixtures
Common test data patterns:
Code
Coverage Goals
Priority 1 (Business Critical)
- Auth domain - Current: 20.2%, Target: 80%
- Organizations domain - Current: 3.3%, Target: 70%
- Pipelines domain - Current: 12.8%, Target: 70%
- Artifacts domain - Current: 17.2%, Target: 70%
- Tools domain - Current: 0.0%, Target: 60%
- Users domain - Current: 12.2%, Target: 60%
Priority 2 (Infrastructure)
- Config package - Current: 47.2%, Target: 50%
- Sessions package - Current: 27.2%, Target: 60%
- Database package - Target: 60%
- Storage package - Target: 60%
Priority 3 (Supporting)
- Server package - Target: 40%
- Health checks - Target: 50%
- CLI tools - Target: 30%
Future Improvements
- E2E Tests: Add end-to-end API tests with full server startup
- Performance Tests: Add benchmarks for critical paths
- Fuzz Testing: Add fuzzing for input validation
- Contract Tests: Ensure API compatibility with OpenAPI spec
- Load Tests: Add k6 or similar for load testing
- Mutation Testing: Consider adding mutation testing for test quality
Contributing
When adding new tests:
- Follow established patterns in existing test files
- Include both success and error cases
- Use descriptive test names
- Update this documentation if introducing new patterns
- Ensure all tests pass with
make test
- Check coverage with
make test-coverage
Last modified on