The Cloud has comprehensive test coverage across all layers, ensuring reliability and maintainability of the codebase.
| Module | Coverage | Status |
|---|---|---|
| pkg/sdk | 95.3% | ✅ Excellent |
| internal/repositories/postgres | 75.0% | ✅ Good |
| pkg/audit | 100% | ✅ Perfect |
| pkg/ratelimit | 100% | ✅ Perfect |
| pkg/util | 85.7% | ✅ Very Good |
| pkg/crypto | 75.8% | ✅ Good |
| internal/core/services | 84.3% | ✅ Very Good |
| internal/handlers | 90.8% | ✅ Excellent |
| pkg/httputil | 98.0% | ✅ Perfect |
Run all tests:
go test ./...Run tests with coverage:
go test -coverprofile=coverage.out ./...View coverage in browser:
go tool cover -html=coverage.outView coverage summary:
go tool cover -func=coverage.out | grep totalRun tests for specific package:
# Test SDK only
go test ./pkg/sdk/...
# Test repositories only
go test ./internal/repositories/postgres/...
# Test services only
go test ./internal/core/services/...# Run all tests
make test
# Run tests with coverage
make test-coverage
# Run benchmarks
make benchmarkLocated alongside source code with *_test.go suffix.
SDK Tests (pkg/sdk/*_test.go):
- Test SDK client methods using httptest
- Mock HTTP responses for all API operations
- No external dependencies required
- Coverage: 95.3%
Example test structure:
func TestClient_CreateQueue(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Mock server response
}))
defer server.Close()
client := NewClient(server.URL, "test-api-key")
result, err := client.CreateQueue(...)
assert.NoError(t, err)
assert.NotNil(t, result)
}Service Tests (internal/core/services/*_test.go):
- Use mock repositories and dependencies
- Test business logic in isolation
- Shared mocks defined in
shared_test.go - Coverage: 84.3%
Example test structure:
func TestQueueService_CreateQueue(t *testing.T) {
mockRepo := new(MockQueueRepository)
mockEventSvc := new(MockEventService)
svc := NewQueueService(mockRepo, mockEventSvc, ...)
mockRepo.On("Create", ctx, mock.Anything).Return(nil)
result, err := svc.CreateQueue(ctx, "test-queue", nil)
assert.NoError(t, err)
mockRepo.AssertExpectations(t)
}Handler Tests (internal/handlers/*_test.go):
- Test HTTP handlers using httptest
- Mock service layer
- Validate HTTP responses and status codes
- Coverage: 90.8%
Repository Tests (internal/repositories/postgres/*_test.go):
- Use pgxmock for database mocking
- Test SQL queries and data mapping
- No real database required for unit tests
- Coverage: 75.0%
Example test structure:
func TestQueueRepository_Create(t *testing.T) {
mock, err := pgxmock.NewPool()
assert.NoError(t, err)
defer mock.Close()
repo := NewQueueRepository(mock)
mock.ExpectExec("INSERT INTO queues").
WithArgs(queue.ID, queue.Name, ...).
WillReturnResult(pgxmock.NewResult("INSERT", 1))
err = repo.Create(ctx, queue)
assert.NoError(t, err)
}Shared Mocks (internal/core/services/shared_test.go):
- Centralized mock implementations
- Reusable across service tests
- Mock interfaces for:
- Repositories (Queue, Cache, Instance, VPC, etc.)
- Services (Event, Audit, Compute)
- External dependencies (Docker, Libvirt)
Test Helpers:
// Creating test context with user ID
ctx := appcontext.WithUserID(context.Background(), uuid.New())
// Setting up mock expectations
mock.On("MethodName", arg1, arg2).Return(result, nil)
mock.On("MethodName", mock.Anything).Return(result, nil)
mock.On("MethodName", mock.MatchedBy(func(x Type) bool {
return x.Field == expectedValue
})).Return(result, nil)-
Test naming convention:
- Function:
TestFunctionName_Scenario - Example:
TestCreateQueue_Success,TestCreateQueue_Unauthorized
- Function:
-
Table-driven tests for multiple scenarios:
func TestCreateQueue(t *testing.T) {
tests := []struct {
name string
input string
wantErr bool
}{
{"success", "valid-name", false},
{"empty name", "", true},
{"too long", strings.Repeat("a", 300), true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := CreateQueue(tt.input)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.NotNil(t, result)
}
})
}
}- Always clean up mocks:
defer mockRepo.AssertExpectations(t)
defer server.Close()-
Test both success and error cases:
- Happy path (success scenarios)
- Error handling (validation, not found, unauthorized, etc.)
- Edge cases (boundary conditions, nil values, etc.)
-
Use meaningful assertions:
// Good - specific assertions
assert.Equal(t, expected, actual)
assert.Contains(t, err.Error(), "expected message")
// Avoid - too generic
assert.NotNil(t, result)- Overall Project: 76.6% ✅ (Target: 70%+)
- SDK: 95.3% ✅ (Target: 80%+)
- Repositories: 75.0% ✅ (Target: 70%+)
- Services: 84.3% ✅ (Target: 75%+)
- Handlers: 90.8% ✅ (Target: 80%+)
- Overall Project: 65%+
- Critical Packages: 80%+
- All Core Logic: 75%+
Tests are automatically run on:
- Every push to any branch
- Pull requests
- Before deployments
See .github/workflows/ for CI configuration.
- name: Run tests
run: go test -race -coverprofile=coverage.out ./...
- name: Check coverage
run: |
coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "Coverage: $coverage%"
if (( $(echo "$coverage < 55" | bc -l) )); then
echo "Coverage is below 55%"
exit 1
fiRun performance benchmarks:
# Run all benchmarks
go test -bench=. ./internal/core/services/
# Run specific benchmark
go test -bench=BenchmarkInstanceService ./internal/core/services/
# With memory allocation stats
go test -bench=. -benchmem ./internal/core/services/go test -v ./pkg/sdk/...go test -v -run TestCreateQueue ./pkg/sdk/dlv test ./pkg/sdk/ -- -test.run TestCreateQueuefunc TestDebug(t *testing.T) {
t.Logf("Debug info: %+v", someValue)
// Test continues...
}func TestHandler(t *testing.T) {
req := httptest.NewRequest(http.MethodPost, "/api/resource", body)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
}func TestWithContext(t *testing.T) {
userID := uuid.New()
ctx := appcontext.WithUserID(context.Background(), userID)
// Use ctx in test
}func TestTimeDependent(t *testing.T) {
now := time.Now()
// Mock time or use time.Now() consistently
// For mocking time, use interface:
mockClock := new(MockClock)
mockClock.On("Now").Return(now)
}- Check for race conditions:
go test -race - Ensure proper cleanup of resources
- Check for test interdependencies
// Add this to see what calls were made
defer mockRepo.AssertExpectations(t)
// Debug with:
mockRepo.AssertCalled(t, "MethodName", arg1, arg2)# Clear test cache
go clean -testcache
# Re-run with coverage
go test -coverprofile=coverage.out ./...When adding new features:
- Write tests first (TDD approach recommended)
- Ensure coverage doesn't drop below current levels
- Add both positive and negative test cases
- Update this documentation if adding new testing patterns