Skip to main content

Overview

Gitea has a comprehensive test suite covering unit tests, integration tests, and end-to-end tests. All contributions should include tests.

Running Tests

All Tests

Run the complete test suite:
make test

Specific Test Packages

Run tests for a specific package:
# Test a specific package
go test ./modules/git/...

# Test with verbose output
go test -v ./services/repository/...

# Run specific test function
go test -v -run TestCreateRepository ./services/repository/

Database-Specific Tests

make test-sqlite

Test Types

Unit Tests

Unit tests focus on individual functions and methods:
// Example unit test
func TestParseGitURL(t *testing.T) {
    tests := []struct {
        input    string
        expected string
        wantErr  bool
    }{
        {
            input:    "https://github.com/user/repo.git",
            expected: "user/repo",
            wantErr:  false,
        },
        {
            input:    "invalid-url",
            wantErr:  true,
        },
    }
    
    for _, tt := range tests {
        result, err := ParseGitURL(tt.input)
        if tt.wantErr {
            assert.Error(t, err)
        } else {
            assert.NoError(t, err)
            assert.Equal(t, tt.expected, result)
        }
    }
}

Integration Tests

Integration tests verify interactions between components:
// Example integration test
func TestAPICreateRepository(t *testing.T) {
    unittest.PrepareTestEnv(t)
    
    session := loginUser(t, "user1")
    token := getTokenForLoggedInUser(t, session)
    
    req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
        Name:        "test-repo",
        Description: "Test repository",
        Private:     false,
    }).AddTokenAuth(token)
    
    resp := session.MakeRequest(t, req, http.StatusCreated)
    
    var repo api.Repository
    DecodeJSON(t, resp, &repo)
    assert.Equal(t, "test-repo", repo.Name)
}

End-to-End Tests

E2E tests use Playwright for browser automation:
# Run E2E tests
make test-e2e

# Run specific E2E test
pnpm test:e2e -- tests/e2e/repo.test.ts

Writing Tests

Test Structure

Organize tests following Go conventions:
package/
├── file.go           # Implementation
├── file_test.go      # Tests
└── testdata/         # Test fixtures
    └── test-data.json

Test Naming

// Format: Test<FunctionName>_<Scenario>
func TestCreateUser_Success(t *testing.T) {}
func TestCreateUser_DuplicateEmail(t *testing.T) {}
func TestCreateUser_InvalidInput(t *testing.T) {}

Using Test Helpers

Gitea provides test utilities:
import (
    "code.gitea.io/gitea/models/unittest"
    "github.com/stretchr/testify/assert"
)

func TestMyFunction(t *testing.T) {
    // Prepare test database
    unittest.PrepareTestEnv(t)
    
    // Your test code
    result := MyFunction()
    
    // Assertions
    assert.NotNil(t, result)
    assert.Equal(t, expected, result)
}

Test Database Setup

// Initialize test environment with fixtures
unittest.PrepareTestEnv(t)

// Load specific fixtures
unittest.LoadFixtures(t, "user.yml", "repository.yml")

// Assert database state
unittest.AssertExistsAndLoadBean(t, &models.User{ID: 1})
unittest.AssertNotExistsBean(t, &models.User{Name: "nonexistent"})

Test Coverage

Generate Coverage Report

# Run tests with coverage
go test -coverprofile=coverage.out ./...

# View coverage report
go tool cover -html=coverage.out

# Check coverage percentage
go tool cover -func=coverage.out

Coverage Requirements

  • New code should have at least 80% coverage
  • Critical paths (authentication, permissions) should have near 100% coverage
  • Edge cases and error conditions should be tested

Continuous Integration

Tests run automatically on:
  • Every pull request
  • Commits to main branch
  • Nightly builds

CI Test Matrix

Tests run across multiple:
  • Go versions: 1.26.x
  • Databases: SQLite, PostgreSQL, MySQL, MSSQL
  • Operating systems: Linux, macOS, Windows
  • Architectures: amd64, arm64

Benchmarking

Run Benchmarks

# Run all benchmarks
go test -bench=. ./...

# Run specific benchmark
go test -bench=BenchmarkParseGitURL ./modules/git/

# With memory profiling
go test -bench=. -benchmem ./modules/git/

Writing Benchmarks

func BenchmarkParseGitURL(b *testing.B) {
    url := "https://github.com/user/repo.git"
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        _, _ = ParseGitURL(url)
    }
}

Testing Best Practices

Write Clear Tests

  • Use descriptive test names
  • One assertion per test when possible
  • Clear arrange-act-assert structure

Test Edge Cases

  • Empty inputs
  • Nil values
  • Boundary conditions
  • Error scenarios

Keep Tests Fast

  • Mock external dependencies
  • Use table-driven tests
  • Avoid unnecessary sleeps

Make Tests Deterministic

  • Don’t rely on timing
  • Use fixed test data
  • Clean up after tests

Debugging Tests

Verbose Output

# Run with verbose output
go test -v ./...

# Show individual test results
go test -v -run TestSpecificFunction

Debugging with Delve

# Install delve
go install github.com/go-delve/delve/cmd/dlv@latest

# Debug a specific test
dlv test ./services/repository -- -test.run TestCreateRepository

Test Logs

// Use t.Log for debugging
func TestMyFunction(t *testing.T) {
    result := MyFunction()
    t.Logf("Result: %+v", result)
    assert.NotNil(t, result)
}

Troubleshooting

Ensure test database is properly initialized:
# Clean test cache
go clean -testcache

# Reset test environment
rm -rf tests/sqlite.db
make test-sqlite
Increase timeout for slow tests:
go test -timeout 30m ./...
Run tests with race detector:
go test -race ./...

See Also

Contributing

Learn about the contribution process

Building

Build Gitea from source

Architecture

Understand the codebase structure

Build docs developers (and LLMs) love