Skip to main content
Version: Next

UV Run Test Workflow

View Source

Run Python tests using UV (ultra-fast Python package installer and resolver) with a single or multiple Python versions.

Overviewโ€‹

This workflow executes Python tests using UV for dependency management. UV is a modern, extremely fast Python package installer and resolver written in Rust, making it significantly faster than traditional pip or Poetry workflows. It's designed for projects that use UV as their package manager and need to run tests efficiently.

When to Useโ€‹

  • โœ… Your project uses UV for dependency management
  • โœ… You need blazing-fast dependency installation
  • โœ… You want to test across multiple Python versions and operating systems
  • โœ… You prefer modern Python tooling with lockfile support
  • โœ… You need efficient CI/CD pipelines with minimal setup time

Workflow Architectureโ€‹

Inputsโ€‹

Required Inputsโ€‹

InputTypeDescription
test_typestringType of tests to run (e.g., 'unit-test', 'integration-test')

Optional Inputsโ€‹

InputTypeDefaultDescription
test_working_directorystring'./'Working directory for test execution
test_folderstring'./test'Folder path for test code
all_test_items_pathsstring'["./test"]'JSON array of test paths to execute
install_dependency_with_groupstring''UV dependency group to install (e.g., 'test', 'dev')
with-environment-variablesstring''Additional environment variables to set
pre_test_scriptstring''Shell script or bash command to run before tests
max-parallelnumber0Maximum parallel jobs (0 = unlimited)
python-versionsstring'["3.13"]'JSON array of Python versions to test
operating-systemsstring'["ubuntu-latest", "ubuntu-22.04", "macos-latest", "macos-14"]'JSON array of OS to test on

Secretsโ€‹

SecretRequiredDescription
e2e_test_api_tokenNoAPI token for end-to-end tests if needed

Outputsโ€‹

This workflow uploads coverage reports as artifacts:

Artifact NameDescription
coverage_<test_type>_<os>_<python_version>Coverage report file (.coverage)

Usage Examplesโ€‹

Basic Usageโ€‹

name: CI

on: [push, pull_request]

jobs:
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: unit-test
all_test_items_paths: '["./test/unit_test/"]'

Multi-Version Testingโ€‹

jobs:
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: unit-test
python-versions: '["3.11", "3.12", "3.13"]'
operating-systems: '["ubuntu-latest", "macos-latest", "windows-latest"]'
all_test_items_paths: '["./test/unit_test/"]'

With Dependency Groupsโ€‹

jobs:
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: integration-test
install_dependency_with_group: test
test_working_directory: ./
all_test_items_paths: '["./test/integration_test/"]'

With Environment Variablesโ€‹

jobs:
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: unit-test
with-environment-variables: 'DEBUG=1 LOG_LEVEL=debug'
all_test_items_paths: '["./test/"]'

With Pre-Test Scriptโ€‹

jobs:
test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: unit-test
pre_test_script: |
echo "Running pre-test validation..."
curl -s https://slack.com/api/auth.test -H "Authorization: Bearer $SLACK_BOT_TOKEN"
all_test_items_paths: '["./test/unit_test/"]'

End-to-End Testing with Secretsโ€‹

jobs:
e2e-test:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
secrets:
e2e_test_api_token: ${{ secrets.E2E_API_TOKEN }}
with:
test_type: e2e-test
all_test_items_paths: '["./test/e2e/"]'
python-versions: '["3.13"]'
pre_test_script: 'echo "Starting E2E tests..." && ./scripts/setup-test-env.sh'

Complete CI Pipelineโ€‹

name: Complete CI

on: [push, pull_request]

jobs:
unit-tests:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: unit-test
python-versions: '["3.11", "3.12", "3.13"]'
operating-systems: '["ubuntu-latest", "macos-latest"]'
all_test_items_paths: '["./test/unit_test/"]'
max-parallel: 4

integration-tests:
uses: Chisanan232/GitHub-Action_Reusable_Workflows-Python/.github/workflows/rw_uv_run_test.yaml@master
with:
test_type: integration-test
install_dependency_with_group: test
all_test_items_paths: '["./test/integration_test/"]'
python-versions: '["3.13"]'

How It Worksโ€‹

Step 1: Environment Setupโ€‹

The workflow sets up UV and Python:

- uses: astral-sh/setup-uv@v7
with:
python-version: ${{ matrix.python-version }}

Step 2: Virtual Environment Creationโ€‹

Creates a UV-managed virtual environment:

uv venv
. .venv/bin/activate

Step 3: Dependency Installationโ€‹

Option A: Install all dependencies (default)

uv sync --locked --all-extras --dev

Option B: Install specific dependency group

uv pip install --group=<group-name>

Step 4: Pre-Test Script (Optional)โ€‹

If pre_test_script is provided, runs custom commands before tests:

# Example: Verify API connectivity
curl -s https://slack.com/api/auth.test -H "Authorization: Bearer $SLACK_BOT_TOKEN"

# Example: Setup test environment
./scripts/setup-test-env.sh

Common use cases:

  • Verify external service connectivity
  • Setup test databases or mock servers
  • Validate environment variables
  • Run database migrations
  • Initialize test fixtures

Step 5: Test Executionโ€‹

Runs tests using UV's pytest integration:

E2E_TEST_API_TOKEN=${{ secrets.e2e_test_api_token }} uv run pytest <test-path>

Step 6: Coverage Collectionโ€‹

Renames and uploads coverage reports:

mv ./.coverage ./.coverage.<test_type>.<os>-<python-version>

Project Requirementsโ€‹

pyproject.toml Configurationโ€‹

Your project must have a pyproject.toml file with UV configuration:

[project]
name = "my-project"
version = "0.1.0"
description = "My Python project"
requires-python = ">=3.11"
dependencies = [
"requests>=2.31.0",
]

[project.optional-dependencies]
test = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
]
dev = [
"ruff>=0.1.0",
"mypy>=1.7.0",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.uv]
dev-dependencies = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
]

Test Structureโ€‹

Organize tests in a clear directory structure:

project/
โ”œโ”€โ”€ pyproject.toml
โ”œโ”€โ”€ uv.lock
โ”œโ”€โ”€ src/
โ”‚ โ””โ”€โ”€ my_package/
โ”‚ โ””โ”€โ”€ __init__.py
โ””โ”€โ”€ test/
โ”œโ”€โ”€ unit_test/
โ”‚ โ””โ”€โ”€ test_module.py
โ””โ”€โ”€ integration_test/
โ””โ”€โ”€ test_integration.py

Best Practicesโ€‹

1. Lock File Managementโ€‹

Always commit uv.lock to ensure reproducible builds:

uv lock
git add uv.lock
git commit -m "Update dependencies"

2. Dependency Groupsโ€‹

Use UV dependency groups for test dependencies:

[tool.uv]
dev-dependencies = [
"pytest>=7.4.0",
"pytest-cov>=4.1.0",
"pytest-mock>=3.11.0",
]

3. Coverage Configurationโ€‹

Configure coverage in pyproject.toml:

[tool.coverage.run]
source = ["src"]
omit = ["*/tests/*", "*/test_*.py"]

[tool.coverage.report]
exclude_lines = [
"pragma: no cover",
"def __repr__",
"raise NotImplementedError",
]

4. Pytest Configurationโ€‹

Configure pytest in pyproject.toml:

[tool.pytest.ini_options]
testpaths = ["test"]
python_files = "test_*.py"
python_classes = "Test*"
python_functions = "test_*"
addopts = "-v --strict-markers --cov --cov-report=xml"

5. Matrix Strategyโ€‹

Optimize test matrix for efficiency:

with:
python-versions: '["3.11", "3.12", "3.13"]'
operating-systems: '["ubuntu-latest", "macos-latest"]'
max-parallel: 4 # Limit concurrent jobs

Advantages of UVโ€‹

Speed Comparisonโ€‹

ToolDependency InstallationVirtual Environment
UV~1-2 seconds~0.5 seconds
Poetry~30-60 seconds~5-10 seconds
pip~20-40 seconds~3-5 seconds

Key Benefitsโ€‹

  1. ๐Ÿš€ Blazing Fast: 10-100x faster than pip/Poetry
  2. ๐Ÿ”’ Reliable: Lockfile support for reproducible builds
  3. ๐ŸŽฏ Modern: Built with Rust for performance
  4. ๐Ÿ”„ Compatible: Works with standard Python packaging
  5. ๐Ÿ’พ Efficient: Smart caching and parallel downloads

Troubleshootingโ€‹

UV Installation Failsโ€‹

Symptoms:

  • UV setup action fails
  • Version conflicts

Solutions:

  1. Verify UV version in action:
    uses: astral-sh/setup-uv@v7
  2. Check Python version compatibility
  3. Review UV installation logs

Dependency Installation Failsโ€‹

Symptoms:

  • uv sync fails
  • Lock file conflicts

Solutions:

  1. Update uv.lock:
    uv lock --upgrade
  2. Check dependency compatibility
  3. Review pyproject.toml syntax

Tests Not Foundโ€‹

Symptoms:

  • "No tests collected" error
  • Pytest can't find tests

Solutions:

  1. Verify test path is correct:
    all_test_items_paths: '["./test/unit_test/"]'
  2. Check test file naming (must start with test_)
  3. Ensure __init__.py files exist in test directories

Coverage Report Missingโ€‹

Symptoms:

  • No coverage report generated
  • Coverage artifact not uploaded

Solutions:

  1. Verify pytest-cov is installed
  2. Check coverage configuration in pyproject.toml
  3. Ensure tests actually run

Environment Variables Not Setโ€‹

Symptoms:

  • Tests fail due to missing environment variables
  • API tokens not available

Solutions:

  1. Use with-environment-variables input:
    with-environment-variables: 'API_KEY=test DEBUG=1'
  2. Pass secrets properly:
    secrets:
    e2e_test_api_token: ${{ secrets.TOKEN }}

Comparison with Other Test Workflowsโ€‹

Featurerw_uv_run_testrw_run_testrw_poetry_run_test
Dependency ManagerUVpip/uvPoetry
Speedโšก FastestFastModerate
Python Versions3.11+3.8+3.8+
Lock Fileuv.lockrequirements.txtpoetry.lock
Virtual EnvUV managedActions managedPoetry managed
Matrix Testingโœ… Built-inโœ… Built-inโœ… Built-in
Best ForModern projectsSimple projectsPoetry projects

Migration Guideโ€‹

From pip to UVโ€‹

  1. Create pyproject.toml:

    uv init
  2. Import requirements:

    uv add $(cat requirements.txt)
  3. Update workflow:

    # Before
    uses: .../rw_run_test.yaml

    # After
    uses: .../rw_uv_run_test.yaml

From Poetry to UVโ€‹

  1. Convert pyproject.toml:

    # UV can read Poetry's pyproject.toml
    uv sync
  2. Update workflow:

    # Before
    uses: .../rw_poetry_run_test.yaml
    with:
    install_dependency_with_group: test,dev

    # After
    uses: .../rw_uv_run_test.yaml
    with:
    install_dependency_with_group: test

Additional Resourcesโ€‹