はじめに
うう・・・百合子・・・ nikkieです。
先日の@pytest.mark.sphinx
の補完エントリです
目次
まとめ:Sphinx拡張のE2Eを書くには
pytestを使います。
ディレクトリ配置
. └── tests/ ├── roots/ │ └── test-default/ │ ├── conf.py │ └── index.rst ├── __init__.py ├── conftest.py └── test_example.py
conftest.py
では1
from pathlib import Path import pytest pytest_plugins = ["sphinx.testing.fixtures"] collect_ignore = ["roots"] @pytest.fixture(scope="session") def rootdir() -> Path: return Path(__file__).parent / "roots"
test-default
ディレクトリのSphinxプロジェクトを元に、HTMLをビルドするテスト(※先日の記事に詳しいです)
import pytest @pytest.mark.sphinx("html", testroot="default") def test_example(app): app.build() assert (app.outdir / "index.html").exists()
コード全容
rootdir
フィクスチャの上書き
conftest.py
にpytest_plugins = ["sphinx.testing.fixtures"]
を指定した時点で、sphinx.testing.fixtures
が提供するフィクスチャ(やマーカー)が有効になります。
pytest --fixtures
の出力を見ると、そこにはrootdir
というフィクスチャもあります。
% pytest --fixtures ---------------- fixtures defined from sphinx.testing.fixtures ----------------- rootdir [session scope] -- .venv/lib/python3.11/site-packages/sphinx/testing/fixtures.py:45 no docstring available
実装を見に行くと
https://github.com/sphinx-doc/sphinx/blob/v8.0.2/sphinx/testing/fixtures.py#L44-L46
@pytest.fixture(scope='session') def rootdir() -> str | None: return None
None
を返すsessionスコープのフィクスチャです。
conftest.py
に同名のrootdir
フィクスチャをsessionスコープで定義することで、None
ではない値(=roots
ディレクトリへのパス)を返すようにしたと理解しました。
pytestのフィクスチャのドキュメントには、overrideについての項目があります。
https://docs.pytest.org/en/stable/how-to/fixtures.html#overriding-fixtures-on-various-levels
「Override a fixture on a folder (conftest) level」を見て、
sphinx.testing.fixtures
においてはrootdir
フィクスチャはNone
を返す- 私たちが置いた
conftest.py
のディレクトリ以下ではrootdir
フィクスチャは代わりにroots
ディレクトリへのパスを返す
ということではないかと思いました。
conftest.py
にrootdir
フィクスチャを定義した後は、同名のフィクスチャが見つかります
% pytest --fixtures ---------------- fixtures defined from sphinx.testing.fixtures ----------------- rootdir [session scope] -- .venv/lib/python3.11/site-packages/sphinx/testing/fixtures.py:45 no docstring available --------------------- fixtures defined from tests.conftest --------------------- rootdir [session scope] -- tests/conftest.py:10 no docstring available
rootdir
フィクスチャは何をしているのか
app_params
フィクスチャがrootdir
フィクスチャを呼び出しています(ドキュメントの言葉だとrequest)。
https://github.com/sphinx-doc/sphinx/blob/v8.0.2/sphinx/testing/fixtures.py#L71-L78
@pytest.fixture def app_params( # ... rootdir: str, ):
app_params
フィクスチャは(上のテストコードで使った)app
フィクスチャから呼び出されます。
また、@pytest.mark.sphinx
マーカーの処理も担っています。
rootdir
フィクスチャが使われるのはこの箇所
https://github.com/sphinx-doc/sphinx/blob/v8.0.2/sphinx/testing/fixtures.py#L109-L112
if rootdir and not srcdir.exists(): testroot_path = rootdir / ('test-' + testroot) shutil.copytree(testroot_path, srcdir)
shutil.copytreeを使って、test-default
のようなSphinxプロジェクトをsrcdir
にコピーします。
srcdir
はsphinx_test_tempdir
フィクスチャにより、一時ディレクトリへのパスとなります。
sphinx.testing.fixtures
に定義されたrootdir
フィクスチャはNone
を返すので、上書きしない場合Sphinxプロジェクトをコピーするこの箇所は実行されません。
rootdir
はapp_params
フィクスチャの定義には必要、しかしその詳細はテストコードを書くユーザに委ねるという実装になっているのですね。
終わりに
Sphinx拡張のE2Eの書き方の理解がだいぶ深まりました。
マーカーに加え、rootdir
フィクスチャの定義だけでよいので、かなり簡単にE2Eを書き始められますね!
ユーザに詳細を定義させるフィクスチャというのも興味深いと思いました。
参考文献
コミッターtk0miyaさんによるquick note
https://github.com/sphinx-doc/sphinx/issues/7008#issuecomment-573092764
Sphinxのテストコードより、conftest.py
https://github.com/sphinx-doc/sphinx/blob/v8.0.2/tests/conftest.py#L35-L45