Testing Infrastructure
AxonFlow maintains a comprehensive testing infrastructure that ensures reliability, performance, and security across all components. This guide covers our testing philosophy and how to run tests locally.
Testing Pyramid
Our testing strategy follows the industry-standard testing pyramid:
┌─────────────┐
│ E2E / │ ← Fewest tests
│ Load Tests │ (expensive, slow)
┌┴─────────────┴┐
│ Integration │ ← Medium coverage
│ Tests │ (API contracts)
┌┴───────────────┴┐
│ Unit Tests │ ← Most tests
└─────────────────┘ (fast, isolated)
Unit Tests
Unit tests validate individual functions and business logic in isolation. Each Go package contains comprehensive unit tests.
Characteristics:
- Fast execution (milliseconds)
- No external dependencies (databases, APIs mocked)
- High coverage of business logic paths
- Run on every commit via CI
Integration Tests
Integration tests validate interactions between components and external systems.
Characteristics:
- Test database operations with real PostgreSQL
- Verify API contracts between services
- Test connector integrations
- Run before deployments
Load Tests
Load tests validate system performance under sustained traffic.
Characteristics:
- Realistic client behavior (connection pooling, HTTP/2)
- Multiple concurrent users
- Percentile latency tracking (P50, P95, P99)
- Run on-demand or scheduled
Performance Tests
Performance tests track system benchmarks over time.
Characteristics:
- Scheduled execution (hourly, daily, weekly)
- Historical trend tracking
- Regression detection
- Cost-optimized (no LLM calls by default)
Running Tests Locally
Prerequisites
- Go 1.21+ installed
- Docker and Docker Compose (for integration tests)
- Make (optional, for convenience)
Unit Tests
Run all unit tests:
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
# Run tests for a specific package
go test ./platform/agent/...
# Run tests with verbose output
go test -v ./platform/orchestrator/...
Integration Tests
Integration tests require a running PostgreSQL instance:
# Start local infrastructure
docker-compose up -d postgres redis
# Run integration tests
go test -tags=integration ./...
# Clean up
docker-compose down
Benchmarks
Run performance benchmarks:
# Run all benchmarks
go test -bench=. ./...
# Run specific benchmark
go test -bench=BenchmarkPolicyEvaluation ./platform/agent/...
# Compare benchmark results
go test -bench=. ./... > new.txt
benchstat old.txt new.txt
Test Structure
File Naming Conventions
| Pattern | Purpose | Example |
|---|---|---|
*_test.go | Unit tests | policy_test.go |
*_integration_test.go | Integration tests | db_integration_test.go |
*_bench_test.go | Benchmarks | agent_bench_test.go |
Test Organization
Tests are co-located with the code they test:
platform/
├── agent/
│ ├── main.go
│ ├── main_test.go # Unit tests
│ ├── agent_bench_test.go # Benchmarks
│ └── db_auth.go
│ └── db_auth_test.go # Unit tests
├── orchestrator/
│ ├── main.go
│ └── main_test.go
└── connectors/
└── amadeus/
├── connector.go
└── connector_test.go
CI/CD Integration
Tests run automatically in our CI pipeline:
-
On Pull Request:
- All unit tests
- Linting (golangci-lint)
- Security scanning
-
On Merge to Main:
- All unit tests
- Integration tests
- Docker image builds
-
Scheduled (Nightly):
- Full test suite
- Performance benchmarks
- Load tests against staging
Coverage Requirements
We maintain high test coverage standards:
- Critical paths: Comprehensive coverage expected
- Business logic: Focus on edge cases and error handling
- Integration points: Contract testing for external APIs
Coverage reports are generated during CI and visible in pull requests.
Mock Usage
We use standard Go mocking patterns:
Database Mocking (go-sqlmock)
import "github.com/DATA-DOG/go-sqlmock"
func TestDatabaseQuery(t *testing.T) {
db, mock, err := sqlmock.New()
require.NoError(t, err)
defer db.Close()
mock.ExpectQuery("SELECT").WillReturnRows(
sqlmock.NewRows([]string{"id", "name"}).
AddRow(1, "test"),
)
// Test your function
}
HTTP Mocking (httptest)
import "net/http/httptest"
func TestExternalAPI(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status": "ok"}`))
}))
defer server.Close()
// Use server.URL in your tests
}
Next Steps
- Load Testing Methodology - Deep dive into load testing
- Performance Testing Architecture - Scheduled testing infrastructure
- Writing Tests Guide - How to contribute tests