This starter includes comprehensive integration tests for all API endpoints.
All API endpoints are tested:
- ✅ Health check returns OK status
- ✅ Database health monitoring
- ✅ Register new user
- ✅ Register duplicate email (conflict handling)
- ✅ Register with invalid data (validation)
- ✅ Login with valid credentials
- ✅ Login with invalid credentials
- ✅ List users (requires authentication)
- ✅ List users with pagination
- ✅ Get user by ID (requires authentication)
- ✅ Get non-existent user (404 handling)
- ✅ Create user (requires authentication)
- ✅ Update user (requires authentication)
- ✅ Delete user (requires authentication)
- ✅ All endpoints verify authentication requirements
-
Test Database: Create a test database
createdb go_api_starter_test
-
Run Migrations: Apply migrations to test database
export DATABASE_URL="postgresql://postgres:postgres@localhost:5432/go_api_starter_test?sslmode=disable" make migrate-up
# Run all tests
make test
# Run tests with coverage
make test-coverage
# Run tests with verbose output
go test -v ./tests/...# Run only health endpoint tests
go test -v ./tests -run TestHealthEndpoint
# Run only authentication tests
go test -v ./tests -run TestAuthEndpoints
# Run only user management tests
go test -v ./tests -run TestUserEndpointsTests use the following database URL priority:
TEST_DATABASE_URLenvironment variableDATABASE_URLenvironment variable- Default:
postgresql://postgres:postgres@localhost:5432/go_api_starter_test?sslmode=disable
# Use custom test database
export TEST_DATABASE_URL="postgresql://user:pass@localhost:5432/my_test_db?sslmode=disable"
go test ./tests/...Tests are organized in tests/api_test.go:
- setupTestRouter(): Creates a test router with all routes configured
- teardownTest(): Cleans up test data after each test
- TestHealthEndpoint(): Tests health check endpoint
- TestAuthEndpoints(): Tests authentication (register/login)
- TestUserEndpoints(): Tests user CRUD operations
Tests use table-driven patterns for multiple scenarios:
testCases := []struct {
name string
request models.RegisterRequest
want int
}{
// Multiple test cases
}Tests verify:
- JWT token generation on login
- Token validation on protected routes
- Unauthorized access rejection
Tests verify proper HTTP status codes:
200- Success201- Created400- Bad Request (validation errors)401- Unauthorized404- Not Found409- Conflict (duplicate resources)
Tests clean up data using TRUNCATE to ensure isolation between test runs.
Tests run automatically in CI/CD (GitHub Actions):
- Uses PostgreSQL 16 in GitHub Actions
- Tests run on every push and pull request
- See
.github/workflows/ci.ymlfor configuration
When adding new endpoints, follow this pattern:
func TestNewEndpoint(t *testing.T) {
router := setupTestRouter(t)
defer teardownTest(t)
t.Run("test case name", func(t *testing.T) {
// Setup
req := httptest.NewRequest("METHOD", "/api/endpoint", body)
req.Header.Set("Authorization", "Bearer "+token)
w := httptest.NewRecorder()
// Execute
router.ServeHTTP(w, req)
// Assert
assert.Equal(t, http.StatusOK, w.Code)
// ... more assertions
})
}- Use
requirefor setup: Fail fast if setup fails - Use
assertfor validations: Continue testing even if one assertion fails - Clean up data: Always call
teardownTest()to prevent test pollution - Test both success and error cases: Verify error handling
- Test authentication: Verify protected routes require auth
- Use descriptive test names: Make it clear what each test validates
If tests fail with database connection errors:
- Ensure PostgreSQL is running
- Check database exists:
psql -l | grep go_api_starter_test - Verify connection string format
- Check database permissions
If tests fail with migration errors:
- Ensure migrations are up to date:
make migrate-up - Check migration files exist in
migrations/ - Verify database schema matches migrations
If tests interfere with each other:
- Ensure
teardownTest()is called in each test - Use unique test data (unique emails, IDs)
- Consider using database transactions for better isolation