📏

Flutterのテストカバレッジを計測してSlackに投稿するまで

2023/11/30に公開

背景

Flutterを触り始めて3ヶ月ぐらい経つのですが、テストカバレッジに関してもそろそろ貢献していきたいと考えてきました。ということで自分が開発に関わっているアプリケーションのテストカバレッジを計測してみたのですが、18%台であまりよくない数字が出てきました。

「え、こんな低かったんだ」と思うのと同時に、私はこの類の数字はメンバーでどんどん共有していった方が開発組織として健全であると共に、すべての開発プロセスの一歩目は計測することだと思っています。

ということでテストカバレッジ改善プロセスの第一歩として、定期的にカバレッジの数字を共有できる仕組みを作ってみた備忘録です。

1. カバレッジ計測

Flutterのテストカバレッジの計測方法自体は簡単で、まず

$ flutter test --coverage

を実行します。すると coverage/lcov.info というファイルがlocalに生成されます。次にこれをlcov[1]を使ってHTMLに変換します。lcovはHomebrew経由でインストールできます。

$ brew install lcov

// lcov.info -> HTMLへ変換
$ genhtml coverage/lcov.info -o coverage/html

コマンドを実行したディレクトリにcoverage/html/index.htmlが生成されているので、これをブラウザで開くとカバレッジファイルが確認できます。ファイルごとのカバレッジの数字でsortできたりするので色々眺めてみると楽しいです。

2. 改めて要件定義

カバレッジレポートを取得することに成功したので、本題の「定期的にカバレッジの数字を共有できる仕組み」を考えていきます。定期的に共有できる仕組み、といっても色々な方法があると思いますが

  1. 実装が比較的かんたん
  2. メンバーも確認しやすい

といえばSlackだなーと思ったので、ここでは 「SlackとGitHubActionsを組み合わせて月曜日の朝9時にカバレッジをポストする」 というのをやってみることにします。

3. カバレッジを取得するスクリプト

まずはカバレッジレポートからカバレッジの数字を取得します。出力してくれるコマンドとかないかなと思ったんですが、ちょっと調べてなさそうだったので[2]力技で引っこ抜くことにしました。カバレッジレポートのHTMLを見てみると

<td class="headerCovTableEntryLo">18.6&nbsp;%</td>

という形式でカバレッジの数字が格納されているので、これを

$ grep 'headerCovTableEntryLo' coverage/html/index.html | sed 's/[^0-9.]//g'
# => 18.6

で引っこ抜きます(なのでclass属性が変われば当然ですが壊れます🙏)。

4. GitHubActionsでworkflowを組む

あとはSlackにカバレッジを通知するworlkflowを組むだけです。結論以下のようにしています。

name: Flutter Coverage Report

defaults:
  run:
    working-directory: mobile

on:
  schedule:
  #           ┌───────────── minute (0 - 59)
  #           │ ┌─────────── hour (0 - 23)
  #           │ │ ┌───────── day of the month (1 - 31)
  #           │ │ │ ┌─────── month (1 - 12 or JAN-DEC)
  #           │ │ │ │ ┌───── day of the week (0 - 6 or SUN-SAT)
    - cron:  '0 0 * * MON'

jobs:
  flutter-coverage-report:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    env:
      TZ: Asia/Tokyo

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          sparse-checkout: mobile
          ref: develop

      - name: Install dart
        uses: dart-lang/setup-dart@v1.4

      - name: Install fvm
        run: dart --version

      - name: Check Dart Version
        run: dart pub global activate fvm

      - name: Setup flutter
        run: fvm install

      - name: Check Flutter version
        run: fvm flutter --version

      - name: Install dependencies
        run: fvm flutter pub get

      - name: Add dotenv
        run: |
          touch .env
          touch .env.dev

      - name: Test
        run: fvm flutter test --coverage --coverage-path=coverage/lcov.info

      - name: Install LCOV
        run: sudo apt-get -y install lcov

      - name: Generate coverage report
        run: genhtml coverage/lcov.info -o coverage/html

      - name: Measure test coverage
        id: measure-test-coverage
        run: echo "coverage_rate=$(grep 'headerCovTableEntryLo' coverage/html/index.html | sed 's/[^0-9.]//g')" >> $GITHUB_OUTPUT

      - name: Notify to Slack
        uses: slackapi/slack-github-action@v1.24.0
        env:
          SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_INCOMING_WEBHOOK_URL }}
        with:
          payload: |
            {
              "attachments": [
                {
                  "blocks": [
                    {
                      "type": "section",
                      "text": {
                        "type": "mrkdwn",
                        "text": "Flutter test coverage rate: `${{ steps.measure-test-coverage.outputs.coverage_rate }}%`"
                      }
                    }
                  ]
                }
              ]
            }

うまくいくとこんな感じでカバレッジを報告してくれます。

5. アップデート

パッと思いついているのは以下です。時間があるときにまたやってみようと思います。

  • 現状は全体のカバレッジしかレポートしていないので、ディレクトリごとのカバレッジに分けて報告してみる。
  • カバレッジの数字が悪いファイルtop5も表示してみる。
  • HTMLをS3やartifactなどにアップロードしてカバレッジレポートを詳細に確認できるようにする(といっても各人のlocal環境でflutter test --coverageしてもらえればいい気もします)。
  • Slackメッセージが少し味気ないので、カバレッジの数字に合わせてメッセージをカスタマイズしてみる。例: 60%で「いい調子!」80%で「すごい!」など。こういう遊び心は大事にしていきたいです。
脚注
  1. https://github.com/linux-test-project/lcov ↩︎

  2. 5分ぐらいしか調べてないので、「こんな方法あるで」という方がいたらコメントでやさしく教えてくれるとありがたいです。 ↩︎

Discussion