はじめに #
toxとuvで複数バージョンのPythonでテストする方法を解説します。
toxの標準のバックエンドはvirtualenvとpipですが、ライブラリのインストールを高速化するため、uvを使用します。 “tox-uv"というライブラリをインストールすると、自動的にuvがバックエンドに使用されます。
また、本記事の検証環境は以下の通りです。
- Windows 10 Home 22H2
- Python 3.13, 3.14
- tox 4.58.0
- tox-uv 1.36.0
- pytest 9.1.1
toxとnoxの比較 #
toxは複数のPythonバージョンやライブラリのバージョンでテストを実行するためのツールです。 また、noxというtoxと類似したツールもあります。 noxとtoxの比較は以下の通りです。
| tox | nox | |
|---|---|---|
| リリース年 | 2010 | 2018 |
| 設定ファイル形式 | TOML/INI | Python |
| GitHubスター数 | 3.9k | 1.5k |
noxはPythonスクリプトで柔軟なテストフローを記述できます。 環境指定がそれほど複雑でない場合、toxの方が設定を簡単に記述できるため、この記事ではtoxを使用します。
なお古いネット記事では、toxの設定はINIファイルに記述するとありますが、
現在のtox v4系列では設定をTOMLファイル (pyproject.tomlやtox.toml) にも記述できるようになっています。
また、tox, noxともデフォルトではvirtualenvで仮想環境を構築します。 構築を高速化したい場合、どちらもuvをバックエンドに使用できます。 toxの場合、tox-uvをインストールします。 noxの場合、テスト時のコマンドラインでuvを指定します。
ライブラリのインストール #
まず、uvを使って仮想環境を構築します。
toxはflat-layoutではうまく動きにくいため、--libオプションを付けてsrc-layoutにします。
また、Pythonのバージョンは、動作を検証する中で最も古いものにします。
uv init --lib --python 3.13
uv sync次に、以下のコマンドでtoxなどのライブラリを仮想環境にインストールします。
ここでは--devオプションを付けて、開発用ライブラリとしました。
uv add --dev tox tox-uv pytestフォルダ構成 #
ここからテスト用スクリプトtest_sample.pyと、toxの設定ファイルtox.tomlを作成します。
最終的なフォルダ構成は以下のようになります。
src/
tests/
└ test_sample.py
pyproject.toml
tox.tomlテスト用スクリプトの作成 #
testsフォルダに以下のtest_sample.pyというスクリプトを作成します。
def test_function():
assert True以下を実行して、pytest単体のテストに合格することを確認します。
uv run pytesttoxの設定 #
tox.tomlを作成し、以下のように設定を記述します。
env_list = ["3.13", "3.14"]
[env_run_base]
deps = ["pytest>=9"]
commands = [["pytest"]]env_listにはテストを実行するPythonのバージョンを指定します。
また、commandsには実行するコマンドを記述します。
depsには実行に必要なライブラリを記述します。
これがないと、以下のようにPython 3.14環境内のpytestで、なぜかPython 3.13が呼ばれてしまいます。
3.14: commands[0]> pytest
=================== test session starts ===================
platform win32 -- Python 3.13.7, pytest-9.1.1, pluggy-1.6.0depsにおけるライブラリのバージョン指定は省略可能です。
pyproject.tomlの設定 #
pyproject.tomlのproject.requires-pythonには、動作検証するPythonのバージョンがすべて含まれていることを確認します。
[project]
requires-python = ">=3.13"toxの実行 #
以下のコマンドで、tomlを使用してPython 3.13と3.14でテストを実行します。
uv run tox実行中は様々なメッセージが表示されますが、最後に以下の通り表示されればテスト成功です。
3.13: OK (3.95=setup[2.19]+cmd[1.76] seconds)
3.14: OK (3.09=setup[1.00]+cmd[2.09] seconds)
congratulations :) (7.15 seconds)テストが失敗する場合 #
次に、テストが失敗する場合を確認します。
test_sample.pyを以下のように変更します。
これはPython 3.14で導入されたテンプレート文字列 (t-string) です。
Python 3.13で実行するとエラーになります。
def test_function():
name = "Alice"
template = t"Hello, {name}!"
assert Trueこの状態でtoxを実行すると、Python 3.13ではエラーになるため、FAILと表示されます。
> uv run tox
...
3.13: FAIL code 2 (2.39=setup[0.98]+cmd[1.41] seconds)
3.14: OK (1.35=setup[0.46]+cmd[0.89] seconds)
evaluation failed :( (3.84 seconds)このように、toxを使用すると複数のバージョンのPythonで動作を検証できます。