This document describes the testing strategy and practices for the Windshift work management system.
internal/
├── handlers/
│ ├── setup_test.go # Unit tests for setup handlers
│ └── testutils/ # Test utilities (build tag: test)
│ ├── database.go # Database testing helpers
│ └── helpers.go # HTTP testing helpers
├── database/
│ ├── database_test.go # Database initialization tests
│ └── integrity_test.go # Database integrity tests
└── models/
└── models_test.go # Model serialization tests
All test utilities use the //go:build test build tag to ensure they are excluded from production builds.
Test Files:
*_test.go- Automatically excluded from production buildstestutils/*- Explicitly tagged with//go:build test
- Test Coverage:
GetSetupStatus- Fresh vs configured database statesCompleteInitialSetup- Valid and invalid setup requestsGetModuleSettings/UpdateModuleSettings- CRUD operations- Validation errors and edge cases
- Transaction rollback on failures
- Password hashing security
- Test Coverage:
- Fresh database initialization
- Schema creation and migration
- Default data population
- Foreign key constraints
- Index creation
- Test Coverage:
- Foreign key constraint enforcement
- Cascade deletion behavior
- Unique constraint validation
- Transaction safety and rollback
- Hierarchical data integrity
- Index performance validation
- Test Coverage:
- JSON serialization/deserialization
- Field validation
- Password hash exclusion (security)
- Default values
- API contract compliance
- Node.js-based API integration tests
- 61 comprehensive test cases
- Full HTTP request/response validation
- Real database operations
// Create test database
tdb := testutils.CreateTestDB(t, true) // in-memory
defer tdb.Close()
// Assertions
tdb.AssertTableExists(t, "workspaces")
tdb.AssertForeignKeyEnabled(t)
tdb.AssertColumnExists(t, "items", "workspace_id")
tdb.AssertIndexExists(t, "idx_items_workspace_id")
// Test data management
data := tdb.SeedTestData(t)
tdb.ClearAllTables(t)
// Transaction testing
tdb.ExecuteInTransaction(t, func(tx *sql.Tx) error {
// Test operations
return nil
})// Create test requests
req := testutils.CreateJSONRequest(t, "POST", "/api/setup/complete", data)
// Execute requests
rr := testutils.ExecuteRequest(t, handler.CompleteSetup, req)
// Assertions
rr.AssertStatusCode(http.StatusOK)
.AssertContentType("application/json")
.AssertJSONResponse(&response)
// Validation helpers
testutils.AssertValidationError(t, rr, "email is required")
testutils.AssertSuccessResponse(t, rr)# Run all tests
make test
# Run with coverage report
make test-coverage
# Run specific test suites
make test-setup # Setup handler tests
make test-db # Database tests
make test-models # Model tests
# Integration tests
make integration-test# All unit tests
go test -tags="test" -v ./...
# With coverage
go test -tags="test" -coverprofile=coverage.out ./...
go tool cover -html=coverage.out
# Specific packages
go test -tags="test" -v ./internal/handlers
go test -tags="test" -v ./internal/database
go test -tags="test" -v ./internal/models# For integration tests
export API_BASE=http://localhost:8080# Production binary (no test code)
make build
# or
go build -tags="!test" -ldflags="-s -w" -o windshift
# Verify test exclusion
make verify-size
make test-build-exclusion# Development binary (with test utilities)
make dev-build
# or
go build -o windshift_dev- Setup Handlers: 95%+ (critical path)
- Database Operations: 90%+ (data integrity)
- Models: 85%+ (serialization)
- Overall Project: 80%+
- HTML Report:
coverage/coverage.html - Terminal:
make test-coverage
- Pros: Fast, isolated, parallel-safe
- Cons: SQLite-specific behavior only
- Usage: Unit tests, CI/CD pipelines
tdb := testutils.CreateTestDB(t, true) // in-memory- Pros: Persistent, real file I/O testing
- Cons: Slower, requires cleanup
- Usage: Integration tests, file system testing
tdb := testutils.CreateTestDB(t, false) // temp file- Each test gets a fresh database
- Automatic cleanup after tests
- No shared state between tests
data := tdb.SeedTestData(t)
// Provides: WorkspaceID, UserID, StatusCategoryID, StatusID// Clear and rebuild
tdb.ClearAllTables(t)
// Add custom test data as needed- name: Run Go Unit Tests
run: make test-coverage
- name: Verify Binary Size
run: make verify-size
- name: Integration Tests
run: make integration-test# Add to .git/hooks/pre-commit
make test
make lint
make verify-sizefunc TestHandler_Function_Scenario(t *testing.T) {
// Arrange
tdb := testutils.CreateTestDB(t, true)
defer tdb.Close()
// Act
result := functionUnderTest(params)
// Assert
if result != expected {
t.Errorf("Expected %v, got %v", expected, result)
}
}tests := []struct {
name string
input InputType
expected OutputType
shouldFail bool
}{
{"valid case", validInput, expectedOutput, false},
{"error case", invalidInput, nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test implementation
})
}- Always test both success and failure paths
- Verify proper error messages
- Test transaction rollback scenarios
- Validate security measures (password hashing)
- Use in-memory databases for unit tests
- Parallel test execution where safe
- Benchmark critical paths
- Monitor test execution time
- Verify passwords are hashed, not stored plain
- Test bcrypt hash verification
- Ensure password fields are excluded from JSON
- Test parameterized queries
- Validate input sanitization
- Test constraint violations
- Test rollback scenarios
- Verify atomic operations
- Test concurrent access patterns
-
Tests fail in CI but pass locally
- Check for race conditions
- Verify test isolation
- Check environment differences
-
Binary size increased unexpectedly
- Run
make verify-size - Check for missing build tags
- Verify production build flags
- Run
-
Database tests are slow
- Use in-memory databases for unit tests
- Check for proper cleanup
- Optimize test data setup
# Run single test with verbose output
go test -tags="test" -v -run TestSpecificTest ./internal/handlers
# Run with race detection
go test -tags="test" -race ./...
# Profile test execution
go test -tags="test" -cpuprofile=cpu.prof -memprofile=mem.prof ./...- Mutation Testing - Verify test quality
- Property-Based Testing - Generate test cases
- Performance Benchmarks - Track regression
- API Contract Testing - Validate OpenAPI compliance
- Coverage trends over time
- Test execution performance
- Flaky test detection
- Binary size monitoring