GitHub Actionsを使ってコードのテストを行う際、テスト結果を見るだけなら ログを見るだけで十分なことが場合が多いですが、coverageの結果を見ようと思うと テキスト情報だけだとちょっと見づらいこともあります。
なのでcoverageの結果をHTMLで出してくれるツールなどもあるので、 そのcoverageの結果を別のbranchへpushして見れるようにしてみました。
ここではPythonのpytestを使った話です。
- pytestのcoverageの出力
- Pytest Coverage Comment
- coverageブランチにsummaryReportを載せる
- coverageブランチにsummaryReportを載せる
pytestのcoverageの出力
pytest を使ったテストの結果のcoverageを出します。
coverageを出すには別途 pytest-covというプラグインが必要です。
両方ともpipで入れられます。
$ pip install pytest pytest-cov
これで、pytestで--covというオプションが使えるようになり、--cov=srcのようにディレクトリを指定するとその中の
コードをどれだけカバー出来たかを調べてくれるようになります。
pytest-covでは--cov-report=htmlとするとhtmlcovというディレクトリの中にHTMLのレポートを作ってくれます。
ただ、このレポートはcssやjsを含むリッチなHTMLになっていて、これ全体をサイトとして公開するようなことをしないと見れません。
やるのであればGitHub Pagesを使ってこのレポートを表示できるようにする、という方法もありますが、今回はもうちょっとライトにやる方法を使います。
Pytest Coverage Comment
pytestのcoverage結果をいい感じの1 page HTMLに直してくれるActionが公開されています。

こんな感じのレポートを作ってくれます。
Missing(カバーできてない部分)は行数を表していて、それぞれGitHub上のデフォルトブランチのコードの該当部分へのリンクとなっています。
これを使うために、workflow内でのpytestを行うための部分のstepは
- name: Run test
run: pytest --junitxml=pytest.xml --cov-report=term-missing:skip-covered --cov=src tests/ | tee pytest-coverage.txt
のような形で--junitxmlオプションを追加し、また--cov-reportもterm-missing:skip-coveredにしておきます。
また、出力をpytest-coverage.txtというファイルにも書き出すようにします(teeを使ってログにも出すように)。
最後のtestsはテスト用のファイルが入っているディレクトリの指定です。
このあとに以下のようなstepを実行します。
- name: Pytest coverage comment
uses: MishaKav/pytest-coverage-comment@main
id: coverageComment
with:
hide-comment: true
pytest-coverage-path: ./pytest-coverage.txt
junitxml-path: ./pytest.xml
このstepを実行すると、stepのoutputsとしていくつか出力が得られて、その中のsummaryReportというのがMarkdown用の出力になっています。
Pytest Coverage CommentのREADMEの説明だと、
coverageHtml: Html with links to files of missing lines. See the output-examplesummaryReport: Markdown with summaryof: Tests/Skipped/Failures/Errors/Time
となっていますが、実際にはsummaryReportの方はcoverageHtml + Markdown (table)のようになっているので、
summaryReportの方だけを出力するようにすればOKです。
多分以下がこれに関する話。
Duplicated coverage badge · Issue #82 · MishaKav/pytest-coverage-comment
上ではcoverageHtmlとsummaryReportを両方書き出すと重複する部分がある、というレポートに対してcoverageHtmlだけにしてください、となってますが、
summaryReportの方がテーブルが追加されてるのでそちらを使った方が良いかと思います。
coverageブランチにsummaryReportを載せる
通常のmainブランチにpushした際にテストを実行し、そのcoverageの結果をcoverageというブランチに出力することにします。
このcoverageは開発などでも使わないようにします。
全体的な例としてはこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | |
onのトリガー部分ではcoverageだけ外すようにします。
coverageブランチでは.github/workflowsを作らないので無くても実行はされませんが一応。
jobs.test.permissionsの設定はsecrets.GITHUB_TOKENにpushする権限を持たせるために必要です。
以前はすべてのwrite権限を持ってましたが、現在はデフォルトでread onlyになっているので
contentsに対してのwriteを加えるようにするか、もしくはレポジトリの設定ですべてのwrite権限を加える必要があります
1。
coverageブランチに載せるのはmainブランチだけにします。 また、テストが複数のOSやPythonの組み合わせで行われる場合にも1つだけを選んで載せるようにします。
その作業をis_main stepで行って、このflagが1の時だけ後のcoverageブランチへの出力のstepを実行するようにしています。
pytestを行う前の部分でpoetryを実行していますがこれはpoetryを使ったレポジトリの例ということで。
そうでない場合は適当なセットアップを入れてください。また、Run testのところでもpoetryを使ってるのでpoetry runをつけているのでその部分も消してください。
その後はcoverageブランチへレポートを載せるための作業です。
Pytest coverage comment: レポート作りUpdate Readme in coverage branch: coverageブランチへの切り替え(なければ作成)、README.mdにworkflowのstatus badgeとsummaryReportを書き込み。Commit: coverageブランチへのcommitPush: coverageブランチをpush
commitする際にはGitHub Actionsで行ったことがわかるようにユーザーをgithub-actions[bot]にしておきます。
これで以下の例のようにcoverageというブランチでレポートが見られます。
mainブランチのREADMEの方に
1 2 | |
みたいな感じで Shields.ioを使って他のbadgeと並べて リンクを張っておけば見やすいかと思います。
以下のような感じ。
ここにcoverageブランチにあるようなパーセンテージ付きのバッジがあった方がよりよいとは思うのですが、 mainのブランチをGitHub Actionsで変更してしまうとコード変更してpushするたびにcoverage用のcommitが入って汚れてしまいます。
その辺気にしなければ、summaryReport自体をmainのREADMEに載せてしまうのもありだとは思います。
coverageブランチにsummaryReportを載せる
もしmainブランチのcommitが汚れても問題ない、という場合には以下のようにして mainブランチに載せる事もできます。(Pytest Coverage CommentのREADMEで説明されているやり方。)
その場合はmainのREADME.mdの先頭に
1 2 3 4 5 6 7 | |
のようにPytest Coverage Comment用のタグを書いておいて、
Update Readme in coverage branchの以下の部分を以下のUpdate Readme with Coverage Htmlの以下のようなstepに書き換えます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
最後のpushをmainにするのを忘れずに。