🐈

`flutter test`の結果をGitHub ActionのChecks上に出力して結果を見やすくする

2021/11/11に公開

GitHub Action上でflutterのテストを実行した結果を見るとき、jobの実行ログを見るのは少し大変ですよね。どれが成功/失敗したかひと目では分かりづらいですし。

今回は↓のようにテストの結果を見やすい形でChecks上に表示する方法を紹介します。

事前準備

特にありません。テストファイルを準備し、flutter testでテストが実行できる状態にします。

ymlファイルの作成

まずはワークフローを実行するためのymlファイルを、リポジトリ内の.github/workflowsに作成します。名前はお好みで。ここではtest.ymlとします

name: test

on:
  workflow_dispatch:
  pull_request:
    types: [opened, synchronize]
  push:
    branches:
      - main

env:
  FLUTTER_VERSION: '2.5.3'

jobs:
  test:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Cache Flutter dependencies
        uses: actions/cache@v2
        with:
          path: /opt/hostedtoolcache/flutter
          key: ${{ runner.OS }}-flutter-install-cache-${{ env.FLUTTER_VERSION }}

      - name: Install Flutter
        uses: subosito/flutter-action@v1
        with:
          flutter-version: ${{ env.FLUTTER_VERSION }}

      - name: Install dependencies
        run: |
          flutter pub get

      - name: Test
        run: |
          flutter test --machine > test_report.log

      - name: Test Report
        uses: dorny/test-reporter@v1
        if: always()
        with:
          name: 'flutter test'
          path: 'test_report.log'
          reporter: 'flutter-json'
          fail-on-error: 'false'

重要な点に絞って解説します

flutter testの結果をjson形式のものに出力する

テストを実行するためのセットアップが終わった次のステップで、テストの実行をしつつ、その結果をファイルに出力します。

flutter test--machineオプションを付与し、結果をファイルに書き出します。
上記の例ではtest_report.logという名前にしていますが、report.jsonでも問題ないです。拡張子がjsonでないとだめ、というわけではなさそうです。

実際にはこのような出力がされます。

{"protocolVersion":"0.1.1","runnerVersion":null,"pid":18064,"type":"start","time":0}
{"suite":{"id":0,"platform":"vm","path":"/Users/user/src/repo/test/widget_test.dart"},"type":"suite","time":0}
{"test":{"id":1,"name":"loading /Users/user/src/repo/test/widget_test.dart","suiteID":0,"groupIDs":[],"metadata":{"skip":false,"skipReason":null},"line":null,"column":null,"url":null},"type":"testStart","time":1}
{"count":1,"time":9,"type":"allSuites"}

[{"event":"test.startedProcess","params":{"observatoryUri":null}}]
{"testID":1,"result":"success","skipped":false,"hidden":true,"type":"testDone","time":1771}
{"group":{"id":2,"suiteID":0,"parentID":null,"name":"","metadata":{"skip":false,"skipReason":null},"testCount":1,"line":null,"column":null,"url":null},"type":"group","time":1775}
{"test":{"id":3,"name":"Counter increments smoke test","suiteID":0,"groupIDs":[2],"metadata":{"skip":false,"skipReason":null},"line":159,"column":5,"url":"package:flutter_test/src/widget_tester.dart","root_line":14,"root_column":3,"root_url":"file:///Users/user/src/repo/test/widget_test.dart"},"type":"testStart","time":1776}
{"testID":3,"result":"success","skipped":false,"hidden":false,"type":"testDone","time":2466}
{"success":true,"type":"done","time":2488}

テストのID、結果、かかった時間などがjsonオブジェクトとして纏められています

test-reporterを使って結果をChecks上に表示させる

dorny/test-reporter@v1アクションを使って、先程実行したテストの結果をChecks上に見やすい形で表示するようにします。

      - name: Test Report
        uses: dorny/test-reporter@v1
        if: always()
        with:
          name: 'flutter test'
          path: 'test_report.log'
          reporter: 'flutter-json'
          fail-on-error: 'false'

ここでは、前stepのテストの結果に関わらず実行したいため、if: always()を指定しておきます。

その他のパラメータについては次のようになっています

  • name: Checksに表示されるときの項目の名前(job名みたいなもの)
    • 指定する必要がある
  • path: flutter test --machineの結果を出力したファイルのパスを指定
  • reporter: 今回はflutter testの結果を出力したいのでflutter-jsonを指定
  • fail-on-error: テストが失敗している場合に、このアクションの結果もfailにするかどうか。今回はfalseにして、このstep自体は成功と判断させるようにします。

他にも、失敗したテストのみ表示する、サマリーだけを表示する、別のjobでアーティファクトに保存したファイルを読み込んだりするためのオプションなどが準備されています。Usageの項目に詳細が書かれています

例えば、複数のjobで並列でflutter testをshardで分割して実行してアーティファクトに結果を保存、それをtest-reporterpathにカンマ区切りで渡して全てのテスト結果を表示する、といったこともできそうです。

実行結果

今まではjobの実行ログを見に行く必要がありましたが、上記のようにセットアップするとことで、プルリクエストのChecks上に、testを実行したjobとは別に"Flutter test"という項目が追加されており、そこでテストの結果を素早く、見やすい形で確認することができます。

成功の場合
失敗の場合

サンプル

以下のリポジトリにworkflowのymlファイルと、実際にテスト結果を出力したプルリクエストを共有しています。

https://github.com/sgr-ksmt/flutter_test_report_on_github_action_example

Discussion