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ブランチへのcommit
Push
: 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
にするのを忘れずに。