tox: CI Integration & Why Isolation Matters
GitHub Actions Integration
# .github/workflows/test.yml
name: Test
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12']
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- run: pip install tox tox-gh-actions
# tox-gh-actions auto-maps the CI job's Python version to the
# matching tox environment -- no manual mapping needed
- run: tox
# tox-gh-actions.ini (or a [gh-actions] section in tox.ini) declares
# the mapping tox-gh-actions reads:
# [gh-actions]
# python =
# 3.9: py39
# 3.10: py310
# 3.11: py311
# 3.12: py312, lintSame Config, Local and CI
A pure CI matrix (strategy.matrix.python-version with no tox) only solves multi-version testing IN CI -- reproducing a specific version's local failure means manually managing that Python install/virtualenv.
tox centralizes the environment definitions -- the same tox.ini serves both `tox -e py311` run locally and the CI job invoking the same command.
Avoids duplicated/drifting test-invocation logic between "what a developer runs locally" and "what CI actually runs".
Why Isolation Catches Real Bugs
A developer's local environment can have stray packages from unrelated work masking a real dependency-declaration bug.
A published library's classifiers claiming "supports Python 3.9-3.12" is only trustworthy if actually verified per version -- tox's environment matrix is how many maintainers make that claim credible before release.
tox is test-runner-agnostic -- commands can invoke pytest, unittest, or anything else; pytest is just the common convention, not a tox requirement.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free