Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

CodeBuildのテストレポート機能でコードカバレッジレポートがサポートされたから、また使ってケチつけてみた

TL; DR

結論から言えば、オススメです。
下記のような画面を見て、問題なさそうだと思った方は、是非とも使ってみてください。

レポートグループの画面

現在では、未実行ラインを表示/確認ができません。
しかし、実装される未来は近い気がします。

AWS様ありがとうございます、一生ついていきます!
ですが、あともう一声、お願いします!!!

はじめに

2020年5月22日になり、テストレポート機能が一般公開されました。

AWS CodeBuild テストレポートの一般公開が開始

それから早2ヶ月後の7月30日、ついに欲しかったコードカバレッジレポートのサポートがされました。

AWS CodeBuild がコードカバレッジレポートをサポート

この機能がどのようなものなのか、実際に動かして確かめてみたくありませんか?
ということで、実際に試してみます。

なお、本記事は下記の続きとして記載しています。
よろしければ、下記もご覧ください。

CodeBuildのテストレポート機能が一般公開されたから使ってケチつけてみた - Qiita

事前準備

コードカバレッジレポートってなんやねん、という方は、ざっと流し読みしてみてください。

コードカバレッジレポート

ここでいうコードカバレッジレポートは、テスト実行時のソースコードカバレッジ(網羅率)を集計したファイルのことです。

カバレッジ(網羅率)分析とは | ソフトウェアの検証の種類 | テクマトリックス株式会社

JaCoCoが有名ですが、それ以外にも多くのフォーマットがあるみたいです。

CodeBuildのレポート機能では、上記コードカバレッジレポートファイルを組込むことで、カバレッジを可視化できます。
似たようなサービスとして、 CodecovCoveralls が挙げられますね。

実際に試してみた

CodeBuildで、テストレポート機能におけるコードカバレッジレポートの表示動作確認をしてみましょう。

なお、CodeCommitとCodeBuildのプロジェクトの新規作成については、 以前の記事で記載 しているため、省略します。

CodeCommitにソースコードをプッシュする

CodeCommitに、CodeBuildでビルドするためのソースコードをプッシュします。

動作確認ができればなんでも良いので、好きな言語で試してみましょう。
つまり僕は、前回同様Perlで試してみるわけです。

ディレクトリ構造は、下記の通りです。

CodeCommitリポジトリのディレクトリ構造
test-reports-sample/
 |- buildspec.yml # CodeBuildの実行ファイル
 |- lib/
 |   |- sample.pm # テスト対象コード(モジュール)
 |
 |- t/
     |- sample.t # テストコード

まず、テスト対象コードです。

lib/sample.pm
use strict;
use warnings;
use utf8;

package Sample;

sub get_one {
    my ($self, $is_true) = @_;

    print "True¥n" if $is_true;

    return 1;
}

sub get_two {
    return 2;
}

1;

このうち、ブランチカバレッジの表示用に書いている箇所は print "True¥n" if $is_true; の部分です。
$is_true は引数に応じて変化します。
引数が真の場合 (Perlなので 1 などを引数に設定した場合)、 print "True¥n" が実行されます。

次に、テストコードです。

t/sample.t
use strict;
use warnings;
use utf8;

use Test::More;

use lib 'lib';
use sample;

subtest 'サンプルテスト' => sub {
    my $test = "pass";
    ok $test;
};

subtest 'サンプルテスト2' => sub {
    my $expected = 1;

    my $actual = Sample->get_one;

    is $actual, $expected;
};

done_testing;

サンプルテスト については、以前のコードと同じため、説明は省略します。

use lib 'lib'; にて lib/ ディレクトリにパスを通し、 use samplelib/sample.pm モジュールをインポートします。
また、 サンプルテスト2 における Sample->get_one により、 lib/sample.pm モジュールにおける get_one 関数を実行します。

下記2点がポイントです。

  • get_two 関数を呼出していない
  • if $is_true は真になり得ず、ブランチカバレッジは100%にならない

CodeBuildでは、buildspec.ymlファイルにより動作を定義できるため、こちらも作ります。

buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - curl -L https://cpanmin.us/ -o cpanm && mv cpanm /usr/bin/cpanm && chmod +x /usr/bin/cpanm
      - curl -fsSL --compressed https://git.io/cpm > cpm && mv cpm /usr/bin/cpm && chmod +x /usr/bin/cpm
  build:
    commands:
      - cpm install -g TAP::Harness::JUnit
      - cpm install -g Devel::Cover::Report::Clover
      # - prove -lv -j5 --harness TAP::Harness::JUnit sample.t # テストレポートだけを出力する場合のコマンド
      - HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,^t" prove -lvr -j5 --harness TAP::Harness::JUnit t
      - cover -report clover

reports:
  sample-test-report:
    files:
      - junit_output.xml
  sample-coverage-clover-report:
    file-format: CloverXml
    files:
      - cover_db/clover.xml

Devel::Cover::Report::Clover モジュールをインストールすることで、Clover形式のXMLを出力できます。

HARNESS_PERL_SWITCHES="-MDevel::Cover=+ignore,^t" prove -lvr -j5 --harness TAP::Harness::JUnit t コマンドにて、 junit_output.xml テストレポートファイルを生成し、同時にテストカバレッジを計測するため cover_db ディレクトリを生成します。
その後 cover -report clover コマンドにて、Clover形式のXMLである cover_db/clover.xml ファイルを生成します。

上記 cover_db/clover.xml ファイルを、 reports における sample-coverage-clover-report にて、 CloverXml フォーマットを指定して設定します。


以降、前回との差分とPerl固有の内容についての詳細です。

前回のCodeBuildイメージは Amazon Linux だったためか、なぜか依存モジュールをインストールしてくれなくて大変な思いをしました。
今回は Ubuntu イメージにしたことで、 expat-devel のDebian版ライブラリ libexpat1-dev をインストールする必要がなくなり、必要なPerlモジュールだけをインストールするだけで依存モジュールのインストールもしてくれました。



また、 Devel::Cover モジュールの cover コマンドには、JSON形式のコードカバレッジレポートファイルを生成してくれます。
しかし、CodeBuildのテストレポート機能で対応しているSimpleCov JSON形式とは異なるため、正常に読み込んでくれません。
Devel::Cover::Report::Clover 以外であっても、CodeBuildのテストレポート機能が対応している形式で出力してあげれば、正常に読み込んでくれると思います。


CodeBuildで自動テストする

上記3ファイルを入れたリポジトリで、CodeCommit経由でCodeBuildを走らせます。
CodeBuildによるビルドは、手動で構いません。

CodeBuildでビルド通過後にテストレポートを確認する

CodeBuildでビルドが完了したら、テストレポートを確認しましょう。

CodeBuildにtest-reports-sampleビルドプロジェクトを作成し、ビルド結果のレポートタブを開きます。

test-reports-sampleビルドプロジェクトにおけるレポートタブを開いた画面

以前までの画面とは異なり、「タイプ」という項目が追加されています。
また、タイプの中身として「テスト」と「コードカバレッジ」の2種類が存在することがわかります。

では、コードカバレッジである test-report-sample-sample-coverage-clover-report グループのレポートを見てみましょう。

test-report-sample-sample-coverage-clover-reportグループのコードカバレッジレポート結果画面

カバレッジ測定結果として、ラインカバレッジとブランチカバレッジの円グラフがデカデカと載っていることがわかります。
また、 lib/sample.pm ファイルを計測していることが、一覧で表示されていることがわかります。

レポートグループ画面は、下記の通り(再掲)です。
カバレッジの履歴が一眼でわかります。
平均の数値はよくわかりませんが、 こっちは便利そうですね。

レポートグループの画面(再掲)

ただ、ここでわかりづらいのですが、ラインカバレッジとブランチカバレッジは独立している、という点です。
それぞれについて、説明します。

ラインカバレッジとブランチカバレッジの解説

以降は、Perlにおける Devel::Cover モジュール固有の問題である可能性もあるので、話半分で聞いてください。

ラインカバレッジの項目では、1行だけ実行されなかったことがわかります。
ここでいう未実行の1行とは、 get_two 関数における return 2; の行のことを指します。

その証拠に、 get_two 関数を呼出すテストコードを追記した場合、下記のような画面になります。

サンプルテスト3を追加したテストコード(抜粋)
subtest 'サンプルテスト3' => sub {
    my $expected = 2;

    my $actual = Sample->get_two;

    is $actual, $expected;
};

ラインカバレッジ0って何......?

ラインカバレッジだけが100%のコードカバレッジレポート結果画面

つまり、 print "True¥n" if $is_true; の行における print "True¥n" は実行されていないにも関わらず、行単位では実行しているためにラインカバレッジは100%になった、というわけです1

一方、ブランチカバレッジは2つしかありませんが、そのうち1つは print "True¥n" if $is_true;$is_true が 真である場合の実行分岐を指しています。

その証拠に、 $is_true が真になる get_one 関数を呼出すテストコードを追記した場合、下記のような画面になります。
サンプルテスト3は、スキップして実行します。

サンプルテスト4を追加したテストコード(抜粋)
subtest 'サンプルテスト3' => sub {
    plan(skip_all => 'ignore test'); # サンプルテスト3はスキップする

    my $expected = 2;

    my $actual = Sample->get_two;

    is $actual, $expected;
};

subtest 'サンプルテスト4' => sub {
    my $expected = 1;

    my $actual = Sample->get_one(1);

    is $actual, $expected;
};

ブランチカバレッジ0って何......?

ブランチカバレッジだけが100%のコードカバレッジレポート結果画面

ここで注意すべき点としては、ブランチカバレッジはラインカバレッジの上位互換ではない、という点です。
$ C0 \leqq C1 $ という不等式が成立しない点に注意してください。

ちなみに、全てのカバレッジを100%にすると、下記のような表示画面になります。

ラインカバレッジおよびブランチカバレッジが100%のコードカバレッジレポート結果画面

CodeBuildテストレポート機能の利点/欠点

機能自体は理解できたので、CodeBuildテストレポート機能におけるコードカバレッジレポートの利点と欠点を、それぞれ書いていきます。

利点

前回と被る面もありますが、利点を挙げていきます。

グラフィカルなUIでテスト結果が確認できる

以前までは、CodeBuildのテスト結果は全てCloudWatch LogsのCUIライクな表示でしか確認できませんでした。
テストレポートだけでなくコードカバレッジレポートもグラフィカルに表示できることで、テストレポートの必要最低限の機能は満たせたのではないかと考えます。

折れ線グラフがわかりやすい

僕の書いた記事を、AWSの中の人が読んでくださったのか定かではありませんが、折れ線グラフが非常にわかりやすいです。
折れ線グラフであれば直近のカバレッジが見えますし、どれだけカバレッジを増やしているかも一目瞭然です。

別サービスを契約しなくて良い

現在の機能だけでも、CodecovやCoverallsなどの別サービスを契約する必要性は下がります。
CodeCommitを使う際はプライベートリポジトリの場合が多いため、プライベートリポジトリの場合は有料契約になってしまう上記サービスを使わなくても良い点は、利点としてかなり大きいと思います。

欠点

いくつか気になる点はあるので、(また、タイトルでもケチつけると書いちゃったので、)粗探しをします。
ただ、前回よりはずいぶんよくなったと思います。

平均ラインカバレッジ率/平均ブランチカバレッジ率の意味がわからない

直前以外の平均ラインカバレッジ/平均ブランチカバレッジも、あまり使わない気がします。
大事なのは、直前のカバレッジだと思うのですが、なぜ平均値を出しているのか、よくわかりません。
しかも、1度でもテストで失敗してしまうと(理論上)100%には二度と戻らないのも、悲しいです。
単純に、最新カバレッジを表示するのではダメなのでしょうか?

あと、ちょっとしたことですが、カバレッジ率を日本語に訳すと網羅率率ですか???

平均ラインカバレッジ/平均ブランチカバレッジが100%の時の表示が気になる

せっかく頑張って100%にしたのに、 0 は悲しいです。
ここは 100% にしてほしいなーと思います。

レポートグループタイプが固定

一度レポートグループを作成してしまうと、作成したレポートグループのタイプを変更できません。

レポートグループタイプおよびレポートタイプは、 TESTCODE_COVERAGE の2種類があります。
レポートタイプは、 buildspec.yml で指定した file-format で、下記に依存して自動的に設定されます。

The following test report file formats are supported:

  • CucumberJson
  • JunitXml
  • NunitXml
  • TestNGXml
  • VisualStudioTrx

The following code coverage report formats are supported:

  • JaCoCoXml
  • SimpleCov
  • CloverXml
  • CoberturaXml

Build specification reference for CodeBuild - AWS CodeBuild

前者が TEST 、後者が CODE_COVERAGE として、内部処理で分けているみたいです。

また、レポートグループタイプは、最初に buildspec.yml でレポートを自動生成する際に設定した file-format の値に依存したタイプが、これまた自動的に設定されます。

レポートグループタイプは(AWSマネジメントコンソール上でも)変更できないため、レポートグループを削除する or レポートグループ名を変更する、いずれかをしない限り、次のようなエラーが発生し、CodeBuildがエラー終了します。

CLIENT_ERROR: Error in UPLOAD_ARTIFACTS phase:
[CoverageReports: [error creating report: InvalidInputException: Report group type doesn't match expected report type, report group type is TEST, but report type is CODE_COVERAGE]]

翻訳結果:
CLIENT_ERROR:UPLOAD_ARTIFACTSフェーズのエラー:
[CoverageReports: [レポートの作成エラー: InvalidInputException: レポートグループタイプが予期されるレポートタイプと一致しません。レポートグループタイプはTESTですが、レポートタイプはCODE_COVERAGEです]]

つまり、最初に file-format を間違えて設定してしまうと、以降はCodeBuildのフェーズエラーを見ない限りエラー内容に気付けません。
最初に使おうと試行錯誤している利用者には、思わぬ落とし穴になりそうです。

すみませんが、この問題の解決策はすぐには思いつきそうにありません。
今後のアップデートに期待します。

おわりに

タイトルでは貶しているように見えたらごめんなさい。
中身としては、結構ベタ褒めで書いたつもりです。

それだけ、僕はこの機能を求めていました。
AWSの中の人、本当にお疲れ様です!

今後もアップデートがあると信じて、期待しましょう!!!


  1. ラインカバレッジの定義としては、別に間違っていません。これに気をつけるために、ブランチカバレッジという物があるわけです。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What are the problem?