これは.NETでコードカバレッジを取得して、それをGitLabのマージリクエストで確認する方法を書いたブログです。
このブログ及びサンプルプロジェクトは.NETを利用しています。ですが、他の言語でもGitLab側の設定はあまり変わりません。他の言語でも参考になると思います。
GitLabでコードカバレッジを確認する
GitLabのマージリクエストなどでコードカバレッジを確認する方法はいくつかあります。このブログではそれら全ての設定方法を解説していますので、長文になります。ブログを読みながら、設定をしてこうなるのかーと理解するのはかなり大変なので、サンプルプロジェクトを用意して、先に概要をつかめるようにしています。
総カバレッジ率を確認する
お試しのマージリクエストを開いてください。パイプライン #....
のすぐ下辺りで総カバレッジ率を確認できます。
総カバレッジ率
総カバレッジ率は、マージリクエスト以外にも、GitLabプロジェクトのサイドメニューの分析
->リポジトリ
から推移グラフで確認できます。
総カバレッジ率の推移グラフ
(サンプルプロジェクトの推移グラフはデータが少なくて面白くないので、GitLabの公式ドキュメントから画像を引用しています)
変更されたコードのコードカバレッジを確認する
マージリクエストの変更タブにあるコード差分でコードカバレッジを確認できます。
マージリクエストのコード差分でのコードカバレッジ
次の手順で試してみてください。
- お試しのマージリクエストを開きます
変更
タブをクリックします- 緑や赤の縦線がコード差分に表示されるまでリロードしてください
詳細なコードカバレッジレポートを確認する
コードカバレッジの生のデータを見ても、わかる人は少ないと思います。人間が読んでもわかりやすいレポート(一般的にHTML形式)に変換するのが一般的です。それをGitLabから確認できます。
コードカバレッジの概要
クラスごとの詳細なコードカバレッジ
次の手順で試してみてください。
- お試しのマージリクエストを開きます
1 件の公開されたアーティファクトを表示
をクリックして開きますcoverage
->coverage
->index.html
とクリックすると、詳細なカバレッジレポートが表示されます
単体テスト結果を確認する(おまけ)
GitLabは単体テスト結果を表示する機能があります。コードカバレッジとは違いますが、せっかくなのでまとめて紹介します。
次の手順で試してみてください。
- お試しのマージリクエストを開きます
テストの要約...
のところの展開
をクリックすると、マージリクエストで変わったテスト結果だけが表示されます
マージリクエストの単体テスト結果要約
レポート全体を見る
をクリックすると、全ての詳細な単体テスト結果にアクセスできます。
パイプラインの単体テスト結果要約
テスト結果の単体詳細
マージリクエストからだけでなく、各パイプラインのテスト
タブでも確認できます。
GitLabに設定する
それでは.NETのプロジェクトを作成して、コードカバレッジをGitLabで確認できるように設定していきます。
.NETプロジェクトを作る
消費税の計算をする機能を単体テストを行い、そのコードカバレッジを取ります。
現時点の消費税の仕様は次のとおりです。
- 消費税率は一律10%とする
- 小数以下は切り捨てる
後で、これに軽減税率(8%)や消費税なしを仕様を追加し、そのコードカバレッジを分析します。
Visual Studioソリューションの構成は次のとおりです。
プロジェクト名 | |
---|---|
ConsumptionTax | 消費税の計算をするクラスライブラリプロジェクト |
ConsumptionTax.Tests | ConsumptionTax クラスライブラリのテストプロジェクト |
早速プロジェクトを作りましょう。
mkdir gitlab-coverage-dotnet-sample
cd gitlab-coverage-dotnet-sample
dotnet new sln
dotnet new classlib -n ConsumptionTax
dotnet sln add ConsumptionTax
dotnet new xunit -n ConsumptionTax.Tests
dotnet sln add ConsumptionTax.Tests
dotnet add ConsumptionTax.Tests reference ConsumptionTax
ConsumptionTax\消費税.cs
クラスを作成します。(この時点では消費税率は一律10%です)
using System;
namespace ConsumptionTax
{
public class 消費税
{
public static int 消費税額(int 税抜金額)
{
var 税額 = 税抜金額 * 0.10m;
return (int) Math.Floor(税額);
}
}
}
ConsumptionTax.Tests\消費税のテスト.cs
クラスを作成します。
using Xunit;
namespace ConsumptionTax.Tests
{
public class 消費税のテスト
{
[Fact]
public void 税抜100円の消費税額は10円()
{
var actual = 消費税.消費税額(100);
Assert.Equal(10, actual);
}
}
}
クラスを追加したら、単体テストを実行します。
dotnet test
次のように全てのテストが成功することを確認してください。
...
テスト実行を開始しています。お待ちください...
合計 1 個のテスト ファイルが指定されたパターンと一致しました。
成功! -失敗: 0、合格: 2、スキップ: 0、合計: 1、期間: < 1 ms - ...
あとはGitLabにプロジェクトを作成してこのVisual StudioソリューションをGitLabのプロジェクトにプッシュしてください。
GitLabで単体テストの実行
GitLabには単体テストの結果を表示する機能があります。コードカバレッジではありませんが、せっかくですのでこの機能の設定方法も紹介します。
マージリクエストでの単体テスト結果要約
単体テスト結果詳細
GitLabで単体テストの結果を確認するためには、レポートがJUnit形式でなければなりませんので、JUnit形式で出力するテストレポーターを組み込みます。
テストレポーターはいくつかありますが、JunitXml.TestLoggerはGitLab CIでの設定例も紹介されているので、採用します。
まずはテストプロジェクトにJunitXml.TestLoggerを追加します。
dotnet add ConsumptionTax.Tests package JunitXml.TestLogger
公式サイトのGitLab CI/CD の推奨設定を参考にしてJUnit形式のレポートを出力します。次のコマンドを実行します。
dotnet test --test-adapter-path:. --logger:"junit;LogFilePath=../artifacts/{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose"
ファイルartifacts\ConsumptionTax.Tests-test-result.xml
が出力されていることを確認してください。(レポートファイルの出力先は、カレントディレクトリではなく、各テストプロジェクトからの相対ディレクトリなことに注意してください)
そして、GitLab CIに組み込みます。.gitlab-ci.yml
ファイルを次のように作成します。
image: mcr.microsoft.com/dotnet/sdk:5.0
test:
script:
- |
dotnet test \
--test-adapter-path:. \
--logger:"junit;LogFilePath=${CI_PROJECT_DIR}/artifacts/{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose"
artifacts:
reports:
junit:
- ./artifacts/*test-result.xml
artifacts
キーワードを使うと、アーティファクトをアップロードしてGitLabで確認できるようになります。reports
キーワードは特別なアーティファクトのアップロードに用いられます。例えば、junit
キーワードを使ってJUnit形式のレポートをアップロードをすると、そのファイルをGitLabが解析し、テスト結果をGitLabで確認することができるようになります。
もちろん、junit
キーワード以外にも、コードカバレッジレポートをアップロードするためのcobertura
キーワードなど、他にもあります。
.gitlab-ci.yml
ファイルの作成が終わったら、コミットしてGitLabにプッシュしてください。GitLab CIパイプラインが開始され、単体テストが実行されます。
GitLabの該当プロジェクトのサイドメニューからCI/CD
->パイプライン
をクリックし、一番上にある最新のパイプラインをクリックしてください。そこのテスト
タブを開くと単体テストの詳細を見ることができます。
パイプラインのテストタブ
コードカバレッジを取る
.NETの単体テストでコードカバレッジを取る方法は、.NETの公式ドキュメントの単体テストにコードカバレッジを使用するに書かれています。こちらを参考にします。
次のコマンドを実行します。
dotnet test --collect:"XPlat Code Coverage"
ファイルConsumptionTax.Tests\TestResults\....\coverage.cobertura.xml
が出力されているはずです。
このコードカバレッジのXMLファイルは生データで、そのままでは役に立ちません。GitLabでわかりやすく表示する設定をしていきます。
マージリクエストのコード差分でのコードカバレッジ
GitLabのマージリクエストの変更
タブにあるコード差分でコードカバレッジを確認する設定をします。
マージリクエストのコード差分でのコードカバレッジ
単体テスト結果のときのように、reports:cobertura
にコードカバレッジのXMLファイルを添付するだけです。
.gitlab-ci.yml
のtest
ジョブを次のように書き換えます。
test:
script:
- dotnet tool restore
- |
dotnet test \
--test-adapter-path:. \
--logger:"junit;LogFilePath=${CI_PROJECT_DIR}/artifacts/{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose" \
--collect:"XPlat Code Coverage"
artifacts:
reports:
junit:
- ./artifacts/*test-result.xml
cobertura:
- ./**/coverage.cobertura.xml
ただし、.NETのコードカバレッジツールが出力したcoverage.cobertura.xml
をGitLabがうまく処理できない場合があります。それは、コードカバレッジ対象のクラスが一つしかないときです。実際の開発プロジェクトではありえませんが、このプロジェクトは該当します。
そのバグ回避のために、ConsumptionTax\Dummy.cs
ファイルを作成します。(実際の開発プロジェクトでは不要です)
namespace ConsumptionTax
{
public class Dummy
{
// coverlet.collector によるカバレッジの取得は
// カバレッジ対象にできるクラスファイルが複数ないと
// GitLab が認識できる形式にならない。
// そのためのダミーファイル。
public void DummyMethod()
{
}
}
}
修正が終わったら、コミットしてGitLabにプッシュしてください。GitLabプロジェクトのサイドメニューのCI/CD
->パイプライン
をクリックして、該当パイプラインの一番右のボタン->Download test:cobertura
をクリックしてください。コードカバレッジのXMLファイルをダウンロードできます。
coverage.covertura.xmlのダウンロード
これでマージリクエストのコード差分でコードカバレッジを確認できるようになりました。あとでマージリクエストを作成して、分析していきます。
詳細なコードカバレッジレポート
マージリクエストのコード差分で確認できるコードカバレッジは限定的です。変更されていないファイルのコードカバレッジは確認できませんし、クラスごとのカバレッジ率も確認できません。
コードカバレッジを詳細なHTML形式のレポートに変換し、それをGitLabで確認できるようにする設定をします。
コードカバレッジの概要
.NETの公式ドキュメントの単体テストにコードカバレッジを使用するにReportGeneratorを利用したHTML化の方法が書かれていますので、これに参考にします。
ReportGeneratorは.NET Tools版がありますので、これを利用します。
まずはプロジェクトローカルに.NET Toolsをインストールできるようにします。
dotnet new tool-manifest
次にReportGeneratorの.NET Tools版をインストールします。
dotnet tool install dotnet-reportgenerator-globaltool
わかりやすいHTMLレポートを作成します。
dotnet reportgenerator -reports:./**/coverage.cobertura.xml -targetdir:coverage -reporttypes:Html
coverage
フォルダーにファイルindex.html
を始めとしたファイルが生成されています。ファイルcoverage\index.html
をダブルクリックしてウェブブラウザーで表示してくみてください。
最後にこのHTMLファイルをGitLab アーティファクトにアップロードして、GitLab上で確認できるようにします。
なお、この機能はGitLab Pagesを必要とします。自前のGitLabの場合はGitLab Pagesが使えるか事前にご確認ください。
.gitlab-ci.yml
のtest
ジョブを次のように書き換えます。
test:
script:
- dotnet tool restore
- |
dotnet test \
--test-adapter-path:. \
--logger:"junit;LogFilePath=${CI_PROJECT_DIR}/artifacts/{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose" \
--collect:"XPlat Code Coverage"
after_script:
- |
dotnet reportgenerator \
-reports:./**/coverage.cobertura.xml \
-targetdir:coverage \
-reporttypes:Html
artifacts:
when: always
expose_as: coverage
paths:
- coverage/
reports:
junit:
- ./artifacts/*test-result.xml
cobertura:
- ./**/coverage.cobertura.xml
when: always
およびafter_script
は失敗した単体テストがあってもレポートの作成とアーティファクトへのアップロードをするためです。
paths
キーワードで、GitLabにアップロードするアーティファクトにHTMLレポートのフォルダーを指定して、レポートの画像ファイルも含めて全て指定します。
expose_as
キーワードはマージリクエストにアーティファクトへ直接ジャンプするリンクを表示します。今はマージリクエストを作っていないので確認できませんが、次のスクリーンショットのようになります。
マージリクエストのカバレッジレポートへのリンク
GitLabの該当プロジェクトのサイドメニューでCI/CD
->パイプライン
をクリックして、該当パイプラインを表示します。次に、test
ジョブを開いてブラウズ
でindex.html
ファイルを探して表示してください。詳細なコードカバレッジレポートが表示されます。
アーティファクトにアップロードされたレポートは、そのうち削除されます。削除されないようにするには、ジョブページの右にある維持
ボタンをクリックしてください。もしくは、.gitlab-ci.yml
ファイルのexpire_in
キーワードで期限を設定できます。
余談ですが、詳細なレポートグラフをHTMLに変換してGitLabで確認する方法はコードカバレッジだけでなく、他のレポートにも応用ができます。
総カバレッジ率
GitLabで総カバレッジ率を確認できるようにしましょう。
総カバレッジ率
GitLabはGitLab CIのジョブのログに出力される総カバレッジ率の数値を読み込むことができます。
例えば、次はNode.jsのテスティングフレームワークのJestでの出力の一部ですが、GitLabはこの内容から総カバレッジ率を読み取ります。
...
PASS ./sum.test.js
✓ adds 1 + 2 to equal 3 (1 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
sum.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
...
残念ながら、dotnet test --collect:"XPlat Code Coverage"
の出力には総カバレッジ率が含まれていません。HTML化したレポートには含まれていますので、grep 'Line coverage:' coverage/index.html
として、総カバレッジ率をジョブに出力します。(HTMLタグが含まれているのはかっこ悪いですが…)
<tr><th>Line coverage:</th><td>58.3% (7 of 12)</td></tr>
ファイル.gitlab-ci.yml
のtest
ジョブを次のように修正します。
test:
script:
- dotnet tool restore
- |
dotnet test \
--test-adapter-path:. \
--logger:"junit;LogFilePath=${CI_PROJECT_DIR}/artifacts/{assembly}-test-result.xml;MethodFormat=Class;FailureBodyFormat=Verbose" \
--collect:"XPlat Code Coverage"
after_script:
- |
dotnet reportgenerator \
-reports:./**/coverage.cobertura.xml \
-targetdir:coverage \
-reporttypes:Html
- grep 'Line coverage:' coverage/index.html
coverage: '/Line coverage:.*%/'
artifacts:
when: always
expose_as: coverage
paths:
- coverage/
reports:
junit:
- ./artifacts/*test-result.xml
cobertura:
- ./**/coverage.cobertura.xml
coverage: '/Line coverage:.*%/'
は総カバレッジ率が出力されている行を指定するためのものです。
修正が終わったらコミットしてGitLabにプッシュします。
単体テストと同じようにパイプラインからtest
ジョブを開きます。ジョブが完了すると、右上に総カバレッジ率が表示されます。
ジョブの総カバレッジ率
以上でコードカバレッジをGitLabで確認するための設定は全て終わりました。
マージリクエストでコードカバレッジを分析する
設定が終わったので、マージリクエストを作って実際にコードカバレッジを分析してみましょう。
軽減税率の導入
サンプルプロジェクトを利用している人はこのセクションの修正は終わっています。ファイルを修正する必要はありません。
まず、ブランチを作成します。
git checkout -b reduced-tax-rate
軽減税率などの導入のためにクラスを修正していきます。
ファイルConsumptionTax\消費税区分.cs
を追加します。
namespace ConsumptionTax
{
public enum 消費税区分
{
通常,
軽減税率,
なし
}
}
ファイルConsumptionTax\消費税.cs
を次のように修正します。
using System;
using System.ComponentModel;
namespace ConsumptionTax
{
public class 消費税
{
public static int 消費税額(int 税抜金額, 消費税区分 消費税区分)
{
if (消費税区分 == 消費税区分.通常)
{
var 税額 = 税抜金額 * 0.10m;
return (int) Math.Floor(税額);
}
if (消費税区分 == 消費税区分.軽減税率)
{
var 税額 = 税抜金額 * 0.08m;
return (int) Math.Floor(税額);
}
if (消費税区分 == 消費税区分.なし) return 税抜金額;
throw new InvalidEnumArgumentException(nameof(消費税区分), (int) 消費税区分, typeof(消費税区分));
}
}
}
ファイルConsumptionTax.Tests\消費税のテスト.cs
を次のように修正します。コードカバレッジを分析したときに面白くなるように、わざとテストパターンを不足させています。
using Xunit;
namespace ConsumptionTax.Tests
{
public class 消費税のテスト
{
[Fact]
public void 税抜100円の消費税額は10円()
{
var actual = 消費税.消費税額(100, 消費税区分.通常);
Assert.Equal(10, actual);
}
[Fact]
public void 税抜100円の消費税額は8円()
{
var actual = 消費税.消費税額(100, 消費税区分.軽減税率);
Assert.Equal(8, actual);
}
}
}
コミットしてGitLabにプッシュ後、マージリクエストを作成してください。
このブランチのパイプライン処理が完了したら、マージリクエストからテスト結果やコードカバレッジにアクセスできるようになります。
総カバレッジ率
作成したマージリクエストの概要
タブのパイプライン #...
のすぐ下にあるTest coverage...
の部分で、総カバレッジ率とマージリクエストでの増減がわかります。
総カバレッジ率
ここでは総カバレッジ率が71.40%で、master
に比べ4.80%上昇しているのがわかります。
ですが、実際の開発プロジェクトでは、マージリクエストで修正するソースコードの量と全体のソースコードの量を考えると、ほぼ変化しないことが予測されます。総カバレッジ率はともかく、増減値を見てもあまり意味はないでしょう。
また、GitLabの該当プロジェクトのサイドメニューの分析
->リポジトリ
にあるCode coverage statistics...
から総カバレッジ率の推移が確認できます。こちらの推移グラフのほうが分析の役に立ちそうです。
総カバレッジ率の推移グラフ
(サンプルプロジェクトの推移グラフはデータが少なくて面白くないので、GitLabの公式ドキュメントから画像を引用しています)
コード差分でのコードカバレッジ
作成したマージリクエストの変更
タブで、コードカバレッジを確認できます。(緑や赤の縦線が表示されないときはウェブブラウザーをリロードしてみてください)
マージリクエストのコード差分でのコードカバレッジ
緑の縦線がテストで実行された行、赤の縦線がテストで実行されていない行になります。
見ての通り、消費税区分.なし
と異常な消費税区分のテストケースが不足していることを発見できます。テストケースにこれらを加える必要があることがわかりました。
詳細なコードカバレッジレポート
作成したマージリクエストの概要
タブの1 件の公開されたアーティファクトを表示
をクリックし、続けてcoverage
->coverage
->index.html
とクリックすると、詳細なHTML化されたコードカバレッジレポートにアクセスできます。
コード差分でのコードカバレッジで確認できることに加え、変更のないコードのコードカバレッジやクラスごとのカバレッジ率も確認できます。
コードカバレッジの概要
クラスごとの詳細なコードカバレッジ
一般的に、ビジネスロジック中心のクラスはカバレッジ率が高い傾向にあります。ビジネスロジッククラスなのにもかかわらず、他よりカバレッジ率が低いクラスがあれば、クラスの詳細レポートを開いて、テストケース不足がないか分析すると良いでしょう。
最後に
コードカバレッジを利用すると、テストケースが不足しているところを見つけるのに役立ちます。GitLabで(特にマージリクエストで)コードカバレッジを確認できるようにすると大変便利です。
開発者が自身の書いたコードのテストケース不足に気がつく手助けになりますし、レビュアーや品質管理者がレポートにすぐにアクセスできるので、広域な分析がやりやすくなります。
ですが、コードカバレッジでは、不足したテストケースを全て発見できるわけではありません。
今回の分析で見つかった、消費税なしや異常な区分のテストを追加すれば、コードカバレッジ率は100%になります。しかし、実際には小数を切り捨てているかどうかのテストケースが不足しています。(例えば、15円の消費税は1円や、19円の消費税は1円のテストケースが必要)このことはコードカバレッジのレポートからはわかりません。
コードカバレッジを無闇矢鱈に信用するのはよくありませんが、品質の向上のための道具の一つと割り切れば、かなり有用です。
GitLabでコードカバレッジを分析し、品質の向上につなげていきましょう!
サンプルプロジェクトを書き換えたい方向け (おまけ)
- GitLabのプロジェクトの作成で、
プロジェクトのインポート
をクリックします Import project from
でリポジトリURL
をクリックしますGit リポジトリ URL
にhttps://gitlab.com/creationline/gitlab-coverage-dotnet-sample.git
をコピペしますプロジェクトを作成
ボタンをクリックします
この方法でプロジェクトを作成しても、パイプラインが実行されません。パイプラインを手動で実行してください。
- サイドメニューの
CI/CD
->パイプライン
をクリックし、パイプラインページを開きます Run pipeline
をクリックし、Run for branch name or tag
でmaster
ブランチを選択してRun pipeline
をクリックしてパイプラインを開始しますreduced-tax-rate
ブランチも同様にパイプラインを開始します- サイドメニューから
マージリクエスト
をクリックし、reduced-tax-rate
ブランチのマージリクエストをを作成します
以上で完了です。
作成したマージリクエストで、コードカバレッジを確認し、テスト不足を修正してコードカバレッジを再度確認してみてください。