Tox : Tests Python multi-environnements
Mise à jour :
Tox répond à un problème récurrent dans les projets Python : tester son code de manière cohérente sur plusieurs versions de Python et avec des dépendances variées, sans devoir tout gérer manuellement. Sans Tox, il faudrait créer et entretenir plusieurs environnements virtuels, installer les bonnes versions des paquets, puis lancer les tests à la main pour chaque combinaison. C’est fastidieux, source d’erreurs et difficile à reproduire dans une équipe ou une pipeline CI/CD. Tox automatise tout ce processus et garantit que votre code reste fiable, quel que soit le contexte d’exécution.
Fonctionnalités de Tox
Tox est conçu pour simplifier la vie des développeurs et des administrateurs système en automatisant plusieurs tâches récurrentes dans les projets Python. Son principal objectif : vous permettre de tester votre code dans différents environnements Python sans avoir à les gérer manuellement.
-
Gestion multi-environnements : L’une des fonctionnalités phares de Tox est la gestion multiples versions de Python. Grâce à un simple fichier de configuration, vous pouvez exécuter vos tests sur Python 3.8, 3.9, 3.10 et plus encore. Cela garantit que votre code reste fonctionnel sur toutes les versions que vous souhaitez supporter. Pour installer plusieurs versions de Python, vous pouvez utiliser
pyenv
ouasdf
. -
Isolation des environnements : Chaque environnement défini dans Tox est isolé, comme si vous utilisiez un
virtualenv
. Cela signifie que les dépendances installées pour un test ne polluent pas votre environnement global. Vous évitez ainsi les conflits de versions et les surprises en production. -
Automatisation des tâches courantes : Tox ne se limite pas aux tests unitaires.
Il peut aussi :
- Lancer des outils de qualité de code comme
flake8
,black
oupylint
- Exécuter des vérifications de type avec
mypy
; - Générer de la documentation avec
sphinx
; - Publier un paquet sur PyPI;
- Nettoyer les fichiers temporaires ou les caches;
- Lancer des outils de qualité de code comme
-
Extensibilité avec des plugins : Tox dispose aussi d’un système de plugins qui permet d’ajouter des fonctionnalités spécifiques. Par exemple, vous pouvez utiliser le plugin
tox-docker
pour ajouter des services à vos tests. -
Exécution en parallèle : Pour gagner du temps, Tox permet d’exécuter plusieurs environnements en parallèle avec l’option
--parallel
.Cela est particulièrement utile dans les projets complexes où les tests prennent plusieurs minutes.
Toutes ces fonctionnalités font de Tox un outil polyvalent, capable de centraliser et d’automatiser la majorité des vérifications que vous devez faire avant de livrer votre code.
Installation de Tox
Pour installer Tox, il vous suffit d’utiliser pipx
ou pip
:
pipx install tox
ou
pip install tox
Tutoriel de l’utilisation de Tox
Pour illustrer l’utilisation de Tox, nous allons créer une simple application de ligne de commande (CLI) en Python. Cette application affichera un message de salutation personnalisé. Nous utiliserons le module Click pour créer la CLI et Tox pour tester notre application sur plusieurs versions de Python.
Étape 1 : Créer un projet CLI avec Click
Voici la structure de répertoires de notre projet :
treemon_cli/├── src/│ └── mon_cli/│ ├── __init__.py│ └── cli.py├── tests/│ └── test_cli.py├── setup.py├── tox.ini├── requirements.txt
mon_cli/
: Répertoire principal de notre projet.src/
: Répertoire source contenant le code de notre application.mon_cli/
: Répertoire contenant le code de notre application :__init__.py
: Fichier d’initialisation du module.cli.py
: Fichier contenant le code de notre application CLI.
setup.py
: Fichier de configuration pour l’installation de notre projet.tox.ini
: Fichier de configuration pour Tox.requirements.txt
: Fichier contenant les dépendances de notre projet.tests/
: Répertoire contenant les tests de notre application:test_cli.py
: Fichier contenant les tests de notre application.
Pour créer cette structure de projet, vous pouvez exécuter les commandes suivantes :
# 1. Créer le dossier racine du projetmkdir moncli && cd moncli
# 2. Créer l'arborescence du code sourcemkdir -p src/mon_cli
# 3. Créer les fichiers Python de basetouch src/mon_cli/__init__.pycat > src/mon_cli/cli.py << 'EOF'import click
@click.command()@click.option("--name", default="Monde", help="Nom à saluer.")def hello(name): """Affiche un message de salutation.""" click.echo(f"Bonjour, {name} !")
if __name__ == "__main__": hello()EOF
# 4. Créer le fichier de testmkdir -p testscat > tests/test_cli.py << 'EOF'from click.testing import CliRunnerfrom mon_cli.cli import hello
def test_hello_default(): runner = CliRunner() result = runner.invoke(hello) assert result.exit_code == 0 assert "Bonjour, Monde !" in result.output
def test_hello_custom_name(): runner = CliRunner() result = runner.invoke(hello, ["--name", "Alice"]) assert result.exit_code == 0 assert "Bonjour, Alice !" in result.outputEOF
# 5. Créer le fichier setup.pycat > setup.py << 'EOF'from setuptools import setup, find_packages
setup( name="moncli", version="0.1.0", packages=find_packages(where="src"), package_dir={"": "src"}, install_requires=["click"], entry_points={ "console_scripts": [ "moncli = mon_cli.cli:hello", ], },)EOF
# 6. Créer requirements.txtecho "click>=8.1" > requirements.txt
Étape 2 : Création du fichier de configuration tox.ini
Créez un fichier tox.ini
à la racine de notre projet, nous allons utiliser la
commande suivante :
tox quickstart
Ce qui va créer un fichier tox.ini
avec le contenu suivant :
[tox]env_list = py312minversion = 4.25.0
[testenv]description = run the tests with pytestpackage = wheelwheel_build_env = .pkgdeps = pytest>=6commands = pytest {tty:--color=yes} {posargs}
Étape 3 : Exécuter Tox
Lancez :
tox
py312: install_deps> python -I -m pip install 'pytest>=6'.pkg: install_requires> python -I -m pip install 'setuptools>=40.8.0' wheel.pkg: _optional_hooks> python /home/bob/.local/share/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__.pkg: get_requires_for_build_wheel> python /home/bob/.local/share/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__.pkg: build_wheel> python /home/bob/.local/share/pipx/venvs/tox/lib/python3.12/site-packages/pyproject_api/_backend.py True setuptools.build_meta __legacy__py312: install_package_deps> python -I -m pip install clickpy312: install_package> python -I -m pip install --force-reinstall --no-deps /home/bob/Projets/moncli/.tox/.tmp/package/1/moncli-0.1.0-py3-none-any.whlpy312: commands[0]> pytest --color=yes====================================================== test session starts =======================================================platform linux -- Python 3.12.3, pytest-8.3.5, pluggy-1.5.0cachedir: .tox/py312/.pytest_cacherootdir: /home/bob/Projets/monclicollected 2 items
tests/test_cli.py .. [100%]
======================================================= 2 passed in 0.01s ======================================================== py312: OK (3.13=setup[3.03]+cmd[0.10] seconds) congratulations :) (3.16 seconds)
Étape 4 : Ajouter Python 3.11 pour les tests Tox
Pour tester votre projet avec Python 3.11, il faut :
- Installer Python 3.11 localement (via
pyenv
recommandé) - S’assurer que Tox peut le détecter
- Ajouter
py311
à la configurationtox.ini
Dans un premier temps, nous allons installer plusieurs versions de Python avec
pyenv
:
pyenv install 3.10.13pyenv install 3.11.9pyenv install 3.12.2
pyenv global 3.10.13 3.11.9 3.12.2pyenv rehash
Vérifiez :
which python3.11/home/bob/.pyenv/shims/python3.11
Modifier le fichier tox.ini
Ajoutez py310
et py311
à la liste des environnements :
env_list = py310 py311 py312minversion = 4.25.0
[testenv]description = run the tests with pytestpackage = wheelwheel_build_env = .pkgdeps = pytest>=6commands = pytest {tty:--color=yes} {posargs}
4. Lancer les tests sur toutes les versions disponibles
tox
Ou pour les exécuter plus rapidement en parallèle :
tox --parallel
Nous avons maintenant un projet Python qui utilise Tox pour tester notre
application CLI sur plusieurs versions de Python. Vous pouvez facilement ajouter
d’autres environnements ou dépendances en modifiant le fichier tox.ini
. Cela
vous permet de vous concentrer sur le développement de votre application sans
vous soucier de la compatibilité entre les différentes versions de Python.
Commandes utiles de la CLI Tox
La commande tox
propose de nombreuses options pour gérer vos environnements,
exécuter des tests ciblés ou analyser votre configuration. Voici les plus utiles
:
Lister tous les environnements
tox -av
default environments:py310 -> run the tests with pytestpy311 -> run the tests with pytestpy312 -> run the tests with pytest
Affiche la liste des environnements disponibles, avec leurs descriptions si
elles sont définies dans tox.ini
.
Lancer un environnement spécifique
tox -e py311
Permet de tester uniquement Python 3.11.
Passer des arguments à la commande de test
tox -- tests/test_cli.py::test_hello_default
Exécute uniquement un test ciblé, ici test_hello_default
.
Forcer la recréation des environnements
tox --recreate
Utile après une modification de dépendance ou de Python.
Exécuter en parallèle
tox --parallel auto
py312: OK ✔ in 0.78 secondspy311: OK ✔ in 0.8 seconds py310: OK (0.81=setup[0.69]+cmd[0.12] seconds) py311: OK (0.80=setup[0.68]+cmd[0.12] seconds) py312: OK (0.78=setup[0.66]+cmd[0.11] seconds) congratulations :) (0.84 seconds)
Lance les tests en parallèle, pour accélérer l’exécution sur plusieurs cœurs.
Utilisations avancées de Tox
Tox permet bien plus que de simplement exécuter des tests unitaires. Voici des cas d’usage plus poussés :
Intégration d’outils de qualité de code
Vous pouvez configurer des environnements pour :
- Linter le code avec
flake8
- Vérifier les types avec
mypy
- Formater avec
black
[testenv:lint]deps = flake8commands = flake8 src tests
[testenv:typecheck]deps = mypycommands = mypy src
Pour tout exécuter :
tox -e lint,typecheck,py311,py312
Bonnes pratiques avec Tox
Pour tirer le meilleur parti de Tox, voici quelques conseils pratiques :
- Utilisez des noms clairs pour vos environnements (ex.
test
,lint
,doc
). - Séparez les dépendances dans des fichiers dédiés (
requirements-test.txt
,requirements-dev.txt
). - Centralisez la logique dans des scripts Python ou
Makefile
pour faciliter l’exécution manuelle. - Validez la compatibilité des versions de Python avec vos dépendances (via
python_requires
danssetup.py
). - Ajoutez Tox à votre pipeline CI/CD (Gitlab CI, GitHub Actions…) pour automatiser les tests dès chaque commit. Nous verrons cela dans un prochain guide.
Conclusion
Tox est un outil puissant pour automatiser les tests et la qualité de code dans les projets Python. Grâce à sa simplicité d’utilisation et à sa flexibilité, vous pouvez facilement l’intégrer dans votre flux de travail. Que vous soyez un développeur solo ou que vous travailliez dans une grande équipe, Tox vous permet de garantir que votre code fonctionne sur toutes les versions de Python et avec toutes les dépendances nécessaires. En utilisant Tox, vous réduisez le risque d’erreurs et améliorez la qualité de votre code, tout en vous concentrant sur ce qui compte vraiment : le développement de fonctionnalités et la satisfaction de vos utilisateurs.
Pour vous montrer un cas d’utilisation concret, j’ai écrit un guide sur l’utilisation de Tox avec Molecule pour tester vos rôles Ansible. Vous pouvez le trouver ici.