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

# TL; DR

コードカバレッジの表示はできませんので、期待するとガッカリするかもしれません。
今後よくなっていくことを信じて待ちましょう！



# はじめに

AWSのCodeBuildで、2019年11月25日にテストレポートのサポート機能（以降、テストレポート機能と呼ぶ）がプレビュー公開されていました。

参考：[AWS CodeBuild で新たにテストレポートをサポート開始](https://aws.amazon.com/jp/about-aws/whats-new/2019/11/aws-codebuild-adds-support-for-test-reporting/)

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

参考：[AWS CodeBuild テストレポートの一般公開が開始](https://aws.amazon.com/jp/about-aws/whats-new/2020/05/aws-codebuild-test-reporting-is-now-generally-available/)

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

~~決して「昨年末に試してみたけど記事を書損ねて流行に乗遅れたから挽回してみた」記事ではありません。~~



# 事前知識

CodeBuildってなんやねん、テストレポートってなんやねん、という方は、ざっと流し読みしてみてください。


## CodeBuildとは

<img width="1197" alt="CodeBuildイメージ画像 https://youtu.be/iEhKcDaNYrs" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/e74029c3-52d4-21da-3867-7d531de940ae.png">

AWSでCI/CD環境を構築する際にお世話になる、「クラウドで動作する完全マネージド型のビルドサービス」です。

参考：[AWS CodeBuild とは - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/welcome.html)

AWSでサービスをビルドする際や、自動テストを実施したりする際に、よくお世話になります。

似たようなサービスとして、 [GitHub Actions](https://help.github.com/ja/actions/getting-started-with-github-actions/about-github-actions) や [CircleCI](https://circleci.com/ja/) が挙げられます。



## テストレポートとは

ここで言うテストレポートとは、テスト結果のテスト件数や実行時間を集計したファイル（いわゆるJUnitのXMLファイル）のことです。
現在では多種多様なフォーマットがあるので、XMLフォーマット以外にもたくさんあります。

参考：[JUnitの実行結果のXMLフォーマット | Developers.IO](https://dev.classmethod.jp/articles/junit-xml-format/)

CodeBuildのテストレポート機能では、上記テストレポートファイルを組込むことで、テスト結果を可視化できます。
似たようなサービスとして、 [CircleCIにおけるテストメタデータの収集](https://circleci.com/docs/ja/2.0/collect-test-data/) が挙げられますね。

......え、 [Codecov](https://codecov.io/) や [Coveralls](https://coveralls.io/) をなぜ挙げないのか？
そのうちわかります。



# 実際に試してみた

CodeBuildで、実際にテストレポート機能の動作確認をしてみましょう。


## CodeCommitとCodeBuildのプロジェクトを新規作成する

CodeBuildでソースコードをビルドする（今回は、単純に自動テストだけを実施するが、以降この作業をビルドと呼ぶ）ためのプロジェクト、および、CodeBuildにソースコードを喰わせるためのCodeCommitリポジトリを、それぞれ新規作成します。
今回は、動作確認のために新規作成しますが、ほとんどのプロジェクトでは既存のCodeBuildが存在すると思うので、本節は飛ばしても構いません。

また、CodeCommitを使わずにGitHubなどを利用している場合は、CodeCommitは必要ありません。

CodeCommitおよびCodeBuildのプロジェクトを新規作成する方法については、ここでは省略します。

参考：

- [AWS CodeCommit リポジトリの作成 - AWS CodeCommit](https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/how-to-create-repository.html)
- [AWS CodeBuild でのビルドプロジェクトの作成 - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/create-project.html)


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

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

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

まず、テストコードです

```pl:sample.t
use strict;
use warnings;

use Test::More;

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

done_testing;
```

本当に、なんの変哲もない最小単位のテストコードです。

これを実行するためには、下記コマンドを使います。

```bash:sample.tファイルの実行
prove sample.t

# 実行結果
#
# sample.t .. ok
# All tests successful.
# Files=1, Tests=1,  0 wallclock secs ( 0.03 usr  0.01 sys +  0.06 cusr  0.02 csys =  0.12 CPU)
# Result: PASS
```

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

```yaml:buildspec.yml
version: 0.2

phases:
  install:
    commands:
      - yum install -y perl-devel expat-devel
      - 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
      - cpm install -g TAP::Harness::JUnit Test::Deep XML::NamespaceSupport XML::SAX::Base XML::SAX XML::SAX::Expat XML::Simple
      - prove -lv -j5 --harness TAP::Harness::JUnit sample.t

reports:
  sample-test-report:
    files:
      - junit_output.xml
```

`build` フェーズにおける、最後の `prove -lv -j5 --harness TAP::Harness::JUnit sample.t` がテスト実行コマンドです。
「sample.tファイルの実行」との大きな違いとして、 `TAP::Harness::JUnit` ライブラリを用いてテストレポートファイル `junit_output.xml` を生成しています。

また、 reports における sample-test-report で、上記 `junit_outpu.xml` ファイルを取得しています。
ここで、CodeBuildのテストレポート機能で表示されるファイルを指定しています。

<details>
  <summary>以降、Perl固有のCodeBuildでの説明です。</summary>
  <p>
    `install` フェーズでは、 cpm コマンドの実行環境を構築しています。
    `perl-devel` ライブラリは cpanm コマンド（具体的には、依存モジュールである `ExtUtils::MakeMaker`）をインストールする際に、また `expat-devel` ライブラリは `TAP::Harness::JUnit` モジュール（具体的には、依存モジュールである `XML::Parser`）をインストールする際に、それぞれ必要なライブラリです。
  </p>
  <p>
    `build` フェーズでは、 cpm コマンドで、 `TAP::Harness::JUnit` モジュールおよび依存モジュールをインストールしています。
    なぜか依存モジュールを自動でインストールしてくれなかったので、自身で使っているPCにインストールした際に表示された依存モジュールをコピペしました。
    また、 `XML::SAX::Expat` モジュールのインストールが時々失敗しますが、原因は不明です。
  </p>
  <p>
    テストレポートファイル生成には、他にも `TAP::Formatter::JUnit` モジュールがありますが、依存モジュールを自動でインストールしてくれない問題により、 `Moose` モジュールの大量依存モジュールのインストールが大変で、途中で諦めてしまいました。
  <p>
</details>

参考：

- CodeBuildに関するもの
    - [CodeBuild のビルド仕様に関するリファレンス - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-spec-ref.html)
- Perlに関するもの
    - [cpanmをインストールする色んな方法 - ノウハウブログ - カンタローCGI](https://kantaro-cgi.com/blog/perl/install-cpanm.html)
    - [skaji/cpm: fast CPAN client](https://github.com/skaji/cpm)
    - [Test::More - テストを書くためのもう一つのフレームワーク - perldoc.jp](https://perldoc.jp/docs/modules/Test-Simple-0.99/lib/Test/More.pod)
    - [複数 prove して TAP::Harness::JUnit が出力する結果を merge する - soh335 memo](https://soh335.hatenablog.com/entry/2013/10/22/155911)
    - [CentOS7にcpanminusを導入する - 偏った言語信者の垂れ流し](https://tokibito.hatenablog.com/entry/2017/05/17/113909)
    - [[Perl]XML::Parserがインストールできないときの対処法 · DQNEO起業日記](http://dqn.sakusakutto.jp/2012/08/perl_xml-parser.html)
    - [jenkinsでコードメトリクス、カバレッジレポートの表示 - notebook](https://swfz.hatenablog.com/entry/2016/04/12/035656)


## CodeBuildで自動テストする

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

1点だけTispなのですが、CloudWatch Logsへのログ出力オプションはオンにしておくと良いです。
実行フローの確認が容易に出来ます。

参考：[AWS CodeBuild でのビルドの実行 - AWS CodeBuild](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/run-build.html)


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

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

CodeBuildにtest-reports-sampleビルドプロジェクトを作成した場合、下記のような画面でビルド成功がわかると思います。

<img width="800" alt="CodeBuildにおけるtest-reports-sampleプロジェクトのビルドログ画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/f6e138df-88e5-9865-ca6e-5cf3a282025f.png">

その中のレポートタブを選択します。

<img width="800" alt="CodeBuildにおけるtest-reports-sampleプロジェクトのレポート画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/ab09b390-ef5c-2db1-78d6-6679ea48cec9.png">

レポートタブ内には、CodeBuildにおけるビルド時のレポートが、一覧でリンクされます。

そのリンクを選択することで、テストレポート画面に移動します。
今回は、 buildspec.yml ファイルで定義した sample-tests-report のテストレポートを確認します。

<img width="800" alt="CodeBuildにおけるtest-report-sample-sample-test-reportのレポート画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/4580cc60-0cda-8338-5c9d-0b544df57682.png">

レポート名は、 `{CodeBuildのビルドプロジェクト名}-{CodeBuildのテストレポート名}:UUID` となっています。
今回、 test-reports-sample ビルドプロジェクトで sample-test-report を表示する設定にしたため、このようなよくわからない表示になっています。
全テスト項目が通っていること（パスレート 100%）や、テスト実行時間（レポート期間 0.0018秒）がわかります。

また、左上の「レポートグループを表示」ボタンを押下することで、歴代のテストレポートの遷移がわかります。

<img width="800" alt="CodeBuildにおけるtest-reports-sample-sample-test-reportのレポートグループ画面" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/d6f016fe-e00c-236c-403e-7ee10688b9aa.png">

レポートグループ名はレポート名におけるUUIDを除いた際の名前です。

歴代のテスト通過率（パスレート 100%）、平均テスト実行時間（平均レポート期間 0.0018秒）、平均テストケース数（テストケースの実行の平均数 1）がわかると思います。

---

テストが失敗すると、CodeBuild自体も失敗判定となります。

テストが失敗した場合は、次のようなレポート画面になります。

<img width="800" alt="CodeBuildにおけるtest-reports-sampleプロジェクトのレポート画面（失敗時）" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/b53d48e0-3eae-31eb-d1dc-6c2db05029f9.png">

パスレートが 0% となっていることが、ひと目でわかります。

レポートグループ画面については、次の通りです。

<img width="800" alt="CodeBuildにおけるtest-report-sample-sample-test-reportのレポートグループ画面（2回目）" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/75d1ba36-e8f9-ab51-2601-2fdd0b079935.png">

歴代のテスト通過率が半分 (50%) になっていることがわかります。
また、「実行時間およびテスト総数」のグラフが2つになり、「テストレポートの失敗とエラー」のグラフが1つ表示されていることが、痛々しいほどに伝わります。
二度とコケるテストをしたくなくなりますね！



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

機能自体は理解できたので、CodeBuildテストレポート機能の利点と欠点を、それぞれ書いていきます。


## 利点

せっかく作ってくれたのだから、いい面を見つけてあげたいですね。


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

以前までは、CodeBuildのテスト結果は全てCloudWatch LogsのCUIライクな表示でしか確認できませんでした。
これがGUIによるグラフィカルな表示になったことで、見やすくなった......かもしれません。


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

今後のアップデート次第では、CodecovやCoverallsなどの別サービスを契約する必要が無くなる可能性があります。
CodeCommitを使う際はプライベートリポジトリの場合が多いため、プライベートリポジトリの場合は有料契約になってしまう上記サービスを使わなくても良い点は、利点として十分かと思います。

......絵空事にならないことを期待します。


## 欠点

本記事を書くきっかけとなっている内容です。

ずばり、現状のCodeBuildテストレポート機能は、使えるとは言い難いです。
それがなぜなのか、また、どのようなサービスであれば良いのか、例を交えて説明します。


### テストカバレッジを表示できない

最大の欠点は、コードカバレッジを表示できない点だと言えます。

CodeBuildのテストレポート機能は、そもそもコードカバレッジを表示するとは一言も言ってないため、しっかり考えれば納得せざるをえません。
しかし、テストレポート機能と言うからには、やはりコードカバレッジの表示は欲しかったです。

~~だって最初の円グラフを見て、まさかコードカバレッジは出せないなんて思わなかったよ！~~


### 平均テスト通過率／平均実行数の意味がわからない

ぶっちゃけ、直前以外のテスト通過率もテスト実行数も、あまり使わない気がします。
大事なのは、直前のテスト通過率と直前のテスト実行数だと思うのですが、なぜ平均値を出しているのか、よくわかりません。
しかも、1度でもテストで失敗してしまうと（理論上）100%には二度と戻らないのも、悲しいです。

最終のテスト通過率を大きく表示するか、通過率（または成功率）の折れ線グラフにするといいのではないでしょうか。
テスト実行数についても同様です。
折れ線グラフにすることで、テスト量の遷移が伝わりやすいと思います。


### 失敗数グラフが心臓に悪い

一度でもテストで失敗してしまうと、レポートグループ画面の「テストレポートの失敗とエラー」に棒グラフが1つ追加されます。
この項目には、テストが成功しても棒グラフは追加されません。

つまり、失敗後に修正して再テストが成功したとしても、「テストレポートの失敗とエラー」の画面では、失敗していた頃の黒歴史を常に見せつけられるわけです。

例えば、3回目でテストが成功した際の画面は、下記の通りです。

<img width="800" alt="CodeBuildにおけるtest-report-sample-sample-test-reportのレポートグループ画面（3回目）" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216416/b01a9180-f684-9eec-949b-8b9b0ee46980.png">

テストレポート履歴では、最後のテストレポートでステータスが成功になっていることがわかります。
......いや、でも真っ赤なんですけど！

この画面を見て、テストが成功していると感じる人は殆どいないと思います。
このUIはどうにかならなかったんでしょうか。
~~まあUIがよろしくないのはAWSの伝統かもしれませんが。~~

失敗時の棒グラフを表示するのは大事だと思いますが、成功時の棒グラフも同じグラフ内に欲しいですね。

というか、去年のAWSブログには成功時棒グラフがあるのに、なぜ消したんでしょうか。

参考：[Test Reports with AWS CodeBuild | AWS DevOps Blog](https://aws.amazon.com/jp/blogs/devops/test-reports-with-aws-codebuild/)



# おわりに

AWSにおけるCodeBuildのテストレポート機能は、昨年末に新登場したばかりの機能であり、お世辞にもいい機能であるとは思えません。
しかし、今後の進化によっては他サービスを脅かす存在にもなるため、注視していきたい機能です。

何卒、コードカバレッジの導入を、お願いします！！！



# おまけ

本記事は、単なる二番煎じ記事であることを報告します......

参考：[自動テストがより便利に！！CodeBuildのテストレポート機能がGAされました！！ | Developers.IO](https://dev.classmethod.jp/articles/codebuild-test-reporting-ga/)