Codecov で iOS アプリのテストカバレッジを可視化する (GitHub + CircleCI + Codecov)

nobuoka
12

エンジニアリングマネジャーの @nobuoka です。 iOS アプリ 「ゼクシィ」 の開発などを担当しています。

本記事では、「ゼクシィ」 iOS アプリのプロジェクトでテストカバレッジを可視化した取り組みを共有します。 技術的に新しいことや難しいことをしているわけではありませんが、カバレッジ可視化の一つの事例として参考になればと思います。

背景・目的

これまで 「ゼクシィ」 のアプリ開発は社外に発注していたのですが、開発をさらに推進していくため、今年の 8 月から内製開発組織も 「ゼクシィ」 のアプリ開発に関わるようになりました。 我々内製開発チームがプロジェクトに参画した時点で、「ゼクシィ」 の iOS プロジェクトのコードテストに関する状況は下記のとおりでした。

  • iOS アプリ 「ゼクシィ」 のプロジェクトには 2014 年ごろまでに書かれたテストコードが含まれている
    • 当時は日本国内で開発しておりコードテストを実施していたようですが、その後オフショア開発に移行してコードテストはなされなくなったようです
  • ビルドやテストを自動実行する CI ジョブがなく、テストコードのビルドもできない状態になっている

外部品質については手動での動作確認等でちゃんと担保されているものの、コードテストを活用して内部品質を高めたり開発効率を高めるといったことができない状況でした。

コードテストが自動化されていなければやがて保守されなくなるのは必然です。 逆にいうと、コードテスト実行の自動化は最低限必要なものです。 書籍 『レガシーソフトウェア改善ガイド』 にも、『誰かがバージョン管理システムにプッシュするたびに、テストを実行してパッケージをビルドする、標準の CI ジョブ』 は 『人々が頼りにできるように準備すべき最小限のもの』 の一つであると書かれています。

今回の取り組みの目的は、コードテストが継続的・自動的に実施される環境を整備することです。 そのためにコードテストを自動実行する CI ジョブを定義します。 さらに、コードテストのカバレッジを把握しやすくするため、テストカバレッジの可視化も行うことにしました。

利用したツール

下記のツールを利用しました。

  • コードリポジトリ : GitHub
  • CI 環境 : CircleCI
    • fastlane (タスクランナー : テスト実行や Slather によるカバレッジ集計を実行)
    • Slather (カバレッジ集計)
    • Bundler (fastlane や Slather といった gem の管理)
  • カバレッジ可視化 : Codecov

GitHub と CircleCI は RMP の内製開発組織でもともと利用されているものです。 fastlane や Bundler も 「ゼクシィ」 のプロジェクトでもともと利用されていたもので、そのまま利用しました。

カバレッジ可視化ツールの選択肢としては、Codecov や Coveralls といったサービスや SonarQube などの製品があります。 今回は GitHub との連携のしやすさや管理コストの小ささから Codecov と Coveralls で検討しました。 その 2 つの比較では、Codecov の方が UI や機能性で優れていると感じるため、最終的に Codecov を採用しました。 具体的に優れていると感じる機能としては、Coverage Sunburst というグラフィカルにプロジェクト全体のディレクトリ構造とカバレッジの状況を表示できる機能 (詳細は Codecov の公式ドキュメント 「Sunburst」 をご覧ください) などがあります。

Codecov の Coverage Sunburst の図
Codecov の Coverage Sunburst (「ゼクシィ」 iOS アプリでの例)。 単なる図ではなく、特定のディレクトリのみを表示するなど、インタラクティブに操作できる

Slather については、テストカバレッジを Codecov にアップロードするにあたって必ずしも必要ではありませんが、どのソースコードを集計対象にするか設定を行いやすくするために導入しています。

CircleCI でのカバレッジの取得

CircleCI 上で fastlane を用いてコードテストの実行と Slather でのカバレッジ集計を行う方法は、すでに本ブログにて書かれています。 下記の記事を参照してください。

CircleCI 2.0 + fastlane + Slather でコードカバレッジの変化を Slack に通知する

上記記事の内容のうち、カバレッジデータを Cobertura XML フォーマットで出力する、というところまでが Codecov でのカバレッジ可視化に必要な箇所です。 (Slack への通知はしなくても問題ありません。)

Codecov へのカバレッジのアップロード

Codecov にカバレッジ情報をアップロードするために、多くの場合は Codecov Bash uploader が使用されます。 このツールは、環境情報 (Git ブランチの情報など) とカバレッジのレポートを収集し、Codecov にアップロードするものです。 今回もこれを使用して CircleCI から Codecov にアップロードしています。

Slather と Codecov Bash uploader を組み合わせて使う方法は Slather のドキュメント に書かれています。 下記のように、Slather の出力結果の Cobertura XML フォーマットのファイルを -f オプションで指定してあげます。

bash <(curl -s https://codecov.io/bash) -f path/to/xml_report/cobertura.xml -X coveragepy -X gcov -X xcode

-X coveragepy -X gcov -X xcode の部分は、Codecov Bash uploader が行う自動的なカバレッジ収集処理を無効化するフラグです。 上でも述べたとおり、Xcode プロジェクトのテストカバレッジを Codecov にアップロードするために Slather を使用する必要は必ずしもなくて、Codecov Bash uploader によって自動的に収集させることもできます。 今回のように Slather を使用する場合は、gcov などによる自動収集処理を無効化します。 詳細は Codecov Bash uploader のヘルプ (bash <(curl -s https://codecov.io/bash) --help で確認できます) などをご覧ください。

なお、Codecov にアップロードするためには Codecov のトークンを指定する必要があります。 CircleCI の場合、プロジェクト設定の Environment Variables に CODECOV_TOKEN という環境変数を追加して、トークンを設定すれば良いでしょう。

これで Codecov へのテストカバレッジのアップロードまでできました。 実際の Codecov のプロジェクトページは以下のようになりました。 一旦既存のテストコードを全てビルド対象から外したのでカバレッジが低い状態なのですが、ここからカバレッジを上げていきたいと思います!

Codecov のプロジェクトページ

実コード

実際に使用している fastlane や CircleCI の設定の一部を共有します。

fastlane の設定ファイル (fastlane/Fastfile) のテスト実行のためのレーンの設定は下記のとおりです。

lane :tests do
  scan(
    workspace: "Zexy.xcworkspace",
    scheme: "Zexy",
    configuration: "Debug",
    device: "iPhone X",
    derived_data_path: "build/fastlane/derived_data",
    buildlog_path: "build/fastlane/scan_build_log",
    output_directory: "build/fastlane/scan_output",
    output_types: "html,junit",
    output_files: "report.html,report.xml"
    )

  slather(
    workspace: "Zexy.xcworkspace",
    proj: "Zexy.xcodeproj",
    scheme: "Zexy",
    build_directory: "build/fastlane/derived_data",
    output_directory: "build/fastlane/slather",
    ignore: "Pods/**",
    cobertura_xml: true,
    verbose: true
  )
end

CircleCI の設定ファイル (.circleci/config.yml) のうちテスト実行とカバレッジのステップは次のようにしました。

    - run:
        name: Run tests
        command: bundle exec fastlane tests

    - run:
        name: Upload test coverage to Codecov
        command: bash <(curl -s https://codecov.io/bash) -f build/fastlane/slather/cobertura.xml -X coveragepy -X gcov -X xcode
            # This command needs an upload token of Codecov.
            # See : https://docs.codecov.io/docs/about-the-codecov-bash-uploader