Python pytest レポート出力 カスタマイズ

今回は、Pythonのテストフレームワークpytestのレポート出力についてのメモです。
基本的なレポート出力方法と、pyest-htmlフック関数を利用して、
レポート出力内容を少し調整するサンプル内容となっています。

https://pytest-html-plus.readthedocs.io/en/main/cli/cli.html?utm_source=chatgpt.com

バージョン

・Python 3.13.9
・pytest-html 4.1.1
・pytest 9.0.2


インストール

pip install pytest pytest-html py

・requirements.txt

pytest
pytest-html
py

pytest-htmlは、html形式のレポート出力用に利用します。
pyは、レポート内容をカスタマイズする際HTML要素を追加するために利用します。


レポート出力コマンド

# HTML レポートを出力(例: `report/report.html`)
pytest --html=ファイルパス/ファイル名.html --self-contained-html

# JUnit XML を出力(例: `report/report.xml`)
pytest --junitxml=ファイルパス/ファイル名.xml

※xmlは、CI実行を行いGitlabなどのツールで集計用途で作成することがあります。


レポートタイトル指定

レポートに表示したいタイトルなどの指定例です。

pytest report customize sample

・conftest.py

from py.xml import html

def pytest_html_report_title(report):
    # レポートの HTML タイトルを設定
    report.title = "テストレポートタイトル: プロジェクト名"

def pytest_configure(config):
    # レポート右上の Environment / Metadata を追加・編集
    # 既存キーを消したければ pop を使う
    meta = getattr(config, "_metadata", None)
    if meta is not None:
        meta["Project"] = "プロジェクト名"
        meta["Build"] = "2025.12.22"
        meta.pop("Packages", None)  # 不要な既定情報を削除する例

def pytest_html_results_summary(prefix, summary, postfix):
    # レポートのタイトル下などの任意の追記(HTML 要素を追加)
    prefix.append(html.h2("追加情報"))
    prefix.append(html.p("ビルド: 2025.12.22"))
    prefix.append(html.p("実行者: testuser"))

レポート項目追加

実行結果のレポートに説明を表示したいことがよくあります。
pytest report customize sample

以下はアノテーションで、説明を指定しレポート表示できるようにする実装サンプルです。

・conftest.py


from py.xml import html

DESCRIPTION_MAP = {}
DESCRIPTION_INDEX = 1  # 固定インデックス(ここを変更すれば列位置を変えられる)

def pytest_configure(config):
    # マーカーだけは登録しておく(説明マーカーの警告回避)
    config.addinivalue_line("markers", "description(text): test description")

# item(pytest Item)から `description` マーカーの最初の引数を取り出して返す。
# - マーカーが無い、または引数が無ければ空文字を返す(表示しない扱い)。
# - マーカーは個々のテスト関数の装飾で付ける想定。
# - パラメータ化テストやクラス/モジュールに付与したマーカーの取り扱いは
#   必要に応じてここで拡張可能。
def _get_description(item):
    m = item.get_closest_marker("description")
    if m and m.args:
        return str(m.args[0])
    return ""

# テスト収集完了時に呼ばれるフック。
# - 各 item.nodeid をキーに DESCRIPTION_MAP を作成することで
# 後でレポート行に対応する説明を検索できるようにする。
# - nodeid 例: tests/test_XXX.py::test_関数名
# - 注意: report.nodeid と完全一致することが前提。xdist などで nodeid が変わる場合は
# マッチ処理を工夫する(部分一致や正規化)必要がある。
def pytest_collection_modifyitems(config, items):
    for item in items:
        DESCRIPTION_MAP[item.nodeid] = _get_description(item)

# HTML テーブルのセルリストに安全に挿入するユーティリティ。
# - index が現在のセル数以上なら末尾に追加する(拡張対応)。
# - そうでなければ指定位置に挿入して列順を保つ。
# - 負の index を渡すと Python の挙動になるため、必要ならチェックを追加しても良い。
def _safe_insert(cells, index, element):
    if index >= len(cells):
        cells.append(element)
    else:
        cells.insert(index, element)

# pytest-html のテーブルヘッダーに「Description」列を挿入するフック。
# - DESCRIPTION_INDEX で列位置を制御する。
# - 他のプラグインやカスタム列と位置が被らないように index を決めること。
def pytest_html_results_table_header(cells):
    _safe_insert(cells, DESCRIPTION_INDEX, html.th("Description"))

# pytest-html の各テスト行を描画するときに呼ばれるフック。
# - report.nodeid をキーに DESCRIPTION_MAP から説明を取り出して表示する。
# - マップに存在しない(収集時に説明が無かった、あるいは nodeid がずれた)場合は空文字を入れる。
# - nodeid の不一致で説明が出ない問題が起きる場合は、収集時とレポート時の nodeid を
# デバッグ出力して比較すると原因特定しやすくなるかもしれない。
def pytest_html_results_table_row(report, cells):
    desc = DESCRIPTION_MAP.get(report.nodeid, "")
    _safe_insert(cells, DESCRIPTION_INDEX, html.td(desc))

・テストケース

import pytest

@pytest.mark.description("説明")
def test_XXX():

今回のメモは以上となります。

pytestは、デフォルトのレポート出力は簡素なものになっていますが、
比較的自由にカスタマイズできますので、
案件の都合に合わせて調整できます。

こちらのの内容は、pyest-htmlを利用する内容になっていますが、
pytest-html-plusや他のプラグインなどもいくつか提供されていますので、
合うものを選択することをおすすめします。

都内でエンジニアをやっています。 2017年に脱サラ(法人設立)しました。 仕事で調べたことや、気になったことをメモしています。
投稿を作成しました 185

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連投稿

検索語を上に入力し、 Enter キーを押して検索します。キャンセルするには ESC を押してください。

トップに戻る