> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/go-gitea/gitea/llms.txt
> Use this file to discover all available pages before exploring further.

# Testing Gitea

> Run tests and write new tests for Gitea

## 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:

```bash theme={null}
make test
```

### Specific Test Packages

Run tests for a specific package:

```bash theme={null}
# 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

<Tabs>
  <Tab title="SQLite">
    ```bash theme={null}
    make test-sqlite
    ```
  </Tab>

  <Tab title="MySQL">
    ```bash theme={null}
    # Requires MySQL running
    TEST_MYSQL_HOST=localhost:3306 \
    TEST_MYSQL_DBNAME=gitea_test \
    TEST_MYSQL_USERNAME=gitea \
    TEST_MYSQL_PASSWORD=gitea \
    make test-mysql
    ```
  </Tab>

  <Tab title="PostgreSQL">
    ```bash theme={null}
    # Requires PostgreSQL running
    TEST_PGSQL_HOST=localhost:5432 \
    TEST_PGSQL_DBNAME=gitea_test \
    TEST_PGSQL_USERNAME=gitea \
    TEST_PGSQL_PASSWORD=gitea \
    make test-pgsql
    ```
  </Tab>
</Tabs>

## Test Types

### Unit Tests

Unit tests focus on individual functions and methods:

```go theme={null}
// 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:

```go theme={null}
// 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:

```bash theme={null}
# 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

```go theme={null}
// 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:

```go theme={null}
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

```go theme={null}
// 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

```bash theme={null}
# 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

```bash theme={null}
# 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

```go theme={null}
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

<CardGroup cols={2}>
  <Card title="Write Clear Tests" icon="check">
    * Use descriptive test names
    * One assertion per test when possible
    * Clear arrange-act-assert structure
  </Card>

  <Card title="Test Edge Cases" icon="triangle-exclamation">
    * Empty inputs
    * Nil values
    * Boundary conditions
    * Error scenarios
  </Card>

  <Card title="Keep Tests Fast" icon="clock">
    * Mock external dependencies
    * Use table-driven tests
    * Avoid unnecessary sleeps
  </Card>

  <Card title="Make Tests Deterministic" icon="repeat">
    * Don't rely on timing
    * Use fixed test data
    * Clean up after tests
  </Card>
</CardGroup>

## Debugging Tests

### Verbose Output

```bash theme={null}
# Run with verbose output
go test -v ./...

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

### Debugging with Delve

```bash theme={null}
# 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

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

## Troubleshooting

<AccordionGroup>
  <Accordion title="Tests fail with database errors">
    Ensure test database is properly initialized:

    ```bash theme={null}
    # Clean test cache
    go clean -testcache

    # Reset test environment
    rm -rf tests/sqlite.db
    make test-sqlite
    ```
  </Accordion>

  <Accordion title="Tests timeout">
    Increase timeout for slow tests:

    ```bash theme={null}
    go test -timeout 30m ./...
    ```
  </Accordion>

  <Accordion title="Race condition detected">
    Run tests with race detector:

    ```bash theme={null}
    go test -race ./...
    ```
  </Accordion>
</AccordionGroup>

## See Also

<CardGroup cols={2}>
  <Card title="Contributing" href="/development/contributing">
    Learn about the contribution process
  </Card>

  <Card title="Building" href="/development/building">
    Build Gitea from source
  </Card>

  <Card title="Architecture" href="/development/architecture">
    Understand the codebase structure
  </Card>
</CardGroup>
