💬
コード差分に関係するテストだけ実行するpytest-testmon
普段使ってるツールの使ってない機能を使ってみる Advent Calendar 2025です。
pytestの記事で紹介されてたpytest-testmonが気になっていたので使ってみました。
pytest-testmonとは
公式ドキュメント曰く
pytest-testmon is a pytest plugin which selects and executes only tests you need to run
ということで、意味あるテストだけ実行できるようにするプラグインです。
具体的には、ある時点(例えばmainブランチ)でのテスト実行(テストによって呼ばれたコード)を保存しておき、そことの差分に関係あるテストだけを実行します。
試してみる
準備
すでにuvの環境設定・pytestのインストールが出来てる前提でtestmonをインストールから始めます。
> uv add pytest-testmon
サンプルコードとテストコードとしてfizzbuzzを用意します。
def fizzbuzz(n):
if is_fizzbuzz(n):
return "FizzBuzz"
elif is_fizz(n):
return "Fizz"
elif is_buzz(n):
return "Buzz"
else:
return str(n)
def is_fizzbuzz(n):
return n%15 == 0
def is_fizz(n):
return n%3 == 0
def is_buzz(n):
return n%5 == 0
import pytest
from fizzbuzz import fizzbuzz
def test_fizzbuzz():
assert "FizzBuzz" == fizzbuzz(15)
def test_fizz():
assert "Fizz" == fizzbuzz(3)
def test_buzz():
assert "Buzz" == fizzbuzz(5)
試してみる
testmonを付けて実行する時は、--testmonパラメータを付けて実行します。最初の実行は、普通のテストと同様に全テスト実行されます。
> pytest --testmon
普通にテストが実行されます。
> pytest --testmon
============================================================================================== test session starts ==============================================================================================
platform linux -- Python 3.11.11, pytest-9.0.1, pluggy-1.6.0
testmon: new DB, environment: default
We'd like to hear from testmon users! Please go to https://testmon.org/survey to leave feedback.
rootdir: /home/notrogue/project/pytest/pytest_sandbox
configfile: pyproject.toml
plugins: testmon-2.2.0
collected 6 items
test_fizzbuzz.py ...... [100%]
=============================================================================================== 6 passed in 0.05s ===============================================================================================
SQLite3のファイルが作成されます。
> file .testmondata
.testmondata: SQLite 3.x database, user version 14, last written using SQLite version 3047001, writer version 2, read version 2, file counter 2, database pages 13, cookie 0x9, schema 4, UTF-8, version-valid-for 2
もう一回testmonで実行すると、実行はスキップされます。
(変更箇所がなく、テスト実行する必要ないので)
> pytest --testmon
============================================================================================== test session starts ==============================================================================================
platform linux -- Python 3.11.11, pytest-9.0.1, pluggy-1.6.0
testmon: changed files: 0, unchanged files: 2, environment: default
rootdir: /home/notrogue/project/pytest/pytest_sandbox
configfile: pyproject.toml
plugins: testmon-2.2.0
collected 0 items
差分実行を見てみる
testmonの差分実行機能を見るために、fizzのロジックだけ変えてみます。
def is_fizz(n):
return n%4 == 0
期待通り、fizzに関するテストだけ実行されます。
pytest --testmon
============================================================================================== test session starts ==============================================================================================
platform linux -- Python 3.11.11, pytest-9.0.1, pluggy-1.6.0
testmon: changed files: test_fizzbuzz.py, unchanged files: 1, environment: default
rootdir: /home/notrogue/project/pytest/pytest_sandbox
configfile: pyproject.toml
plugins: testmon-2.2.0
collected 3 items / 1 deselected / 2 selected
test_fizzbuzz.py F. [100%]
=================================================================================================== FAILURES ====================================================================================================
___________________________________________________________________________________________________ test_fizz ___________________________________________________________________________________________________
def test_fizz():
> assert "Fizz" == fizzbuzz(3)
E AssertionError: assert 'Fizz' == '3'
E
E - 3
E + Fizz
test_fizzbuzz.py:8: AssertionError
============================================================================================ short test summary info ============================================================================================
FAILED test_fizzbuzz.py::test_fizz - AssertionError: assert 'Fizz' == '3'
テスト追加
追加したテストが実行されるかも見てみます。
def test_0():
assert "0" == fizzbuzz(0)
pytest --testmon
============================================================================================== test session starts ==============================================================================================
platform linux -- Python 3.11.11, pytest-9.0.1, pluggy-1.6.0
testmon: changed files: test_fizzbuzz.py, unchanged files: 1, environment: default
rootdir: /home/notrogue/project/pytest/pytest_sandbox
configfile: pyproject.toml
plugins: testmon-2.2.0
collected 4 items
test_fizzbuzz.py F... [100%]
=================================================================================================== FAILURES ====================================================================================================
____________________________________________________________________________________________________ test_0 _____________________________________________________________________________________________________
def test_0():
> assert "0" == fizzbuzz(0)
E AssertionError: assert '0' == 'FizzBuzz'
E
E - FizzBuzz
E + 0
test_fizzbuzz.py:14: AssertionError
===================================================
実行されてますね。
仕組み
SQLite3のテーブルに、テストとそのテストで実行されたファイルの紐づけを持っており、変更されたファイル(のハッシュ)に紐づくテストを探して実行してるようです。
Discussion