iOS アプリのテストカバレッジを SonarQube で集計する
nobuoka
背景・目的
背景
私が関わっている 「ゼクシィ」 iOS アプリプロジェクトでは、Codecov によるテストカバレッジ集計を行っています。 これについては、以前 「Codecov で iOS アプリのテストカバレッジを可視化する (GitHub + CircleCI + Codecov)」 という投稿で紹介しました。
「ゼクシィ」 iOS アプリのプロジェクトでは、静的解析ツールの SonarQube も使っています。 SonarQube にもテストカバレッジ集計の機能がありますので、SonarQube でもカバレッジ集計を行いたいと思います。
本投稿の目的
iOS プロジェクトのテストカバレッジを SonarQube で集計するためのスクリプトが SonarSource 1)SonarQube 開発元 によって公開されているのですが、そのスクリプトをそのまま使うだけではうまく集計できないという問題がありました。
上記問題を解決した fastlane action を作成し、iOS プロジェクトのテストカバレッジを SonarQube で集計できるようにしましたので、その内容を共有します。
iOS プロジェクトのカバレッジを SonarQube で集計する方法
ドキュメントに書かれている方法
SonarQube でテストカバレッジを集計する方法については、SonarQube のドキュメントにまとまっています。
Test Coverage & Execution | SonarQube Docs
iOS プロジェクトの場合、言語は Objective-C か Swift でしょう。 上記ページを見ると、Objective-C と Swift で下記のように別の集計方法が提示されていました。
- Objective-C (C family) :
- gcov で生成されたカバレッジデータを用いる方法
- llvm-cov で生成されたカバレッジデータを用いる方法
- など、いくつかの候補が書かれている
- Swift :
- Xcode 9.2 以下では、llvm-cov で生成されたカバレッジデータを用いる方法
- Xcode 9.3 以降では、xccov で生成したカバレッジデータを SonarQube の包括カバレッジフォーマット (generic coverage format) に変更するスクリプトを用いる方法
Objective-C と Swift の両方を使用している iOS プロジェクトの場合、Objective-C 用の方法と Swift 用の方法のどちらを採用すべきなのかわかりづらいところですが、結論としては Swift の Xcode 9.3 以降向けの方法を採用すれば大丈夫です。 この方法で Objective-C のカバレッジも扱えます。 (試していませんが、llvm-cov のカバレッジデータを用いる方法でも、Objective-C と Swift の両方を扱えると思います。)
ちなみに、llvm-cov は LLVM プロジェクトに含まれるカバレッジツールであり、xccov は Xcode 9.3 で導入されたカバレッジツールです。 xccov については、WWDC 2018 の 「What's New in Testing」 というセッションで説明されています。 私は llvm-cov と xccov の違いや特徴を把握できていないのですが、Xcode に付属している方がより iOS アプリに適しているのではないかと思って xccov を使っています。 (もし llvm-cov と xccov で大きな違いがあるようでしたら教えてもらえると嬉しいです。)
上記の方法を実際に行った場合の問題
上記の方法に書かれている 「xccov で生成したカバレッジデータを SonarQube の包括カバレッジフォーマット (generic coverage format) に変更するスクリプト」 は xccov-to-sonarqube-generic.sh です。
実際にこのスクリプトを用いて包括カバレッジフォーマットに変換して SonarScanner に与えてみたのですが、なぜか SonarQube 上に表示されるカバレッジは 0 % のままでした。
調査したところ、包括カバレッジフォーマットで出力されたファイルの中身に書かれている対象ファイルパスが絶対パスになっていることを発見しました。 同様の現象が下記ページなどでも報告されていましたし、手で相対パスに直して SonarScanner に与えたところカバレッジが集計されたので、絶対ファイルパスになっていることがカバレッジの集計がされない原因のようでした。
そこまでは突き止めたのは良いものの、なぜ xccov-to-sonarqube-generic.sh をそのまま使える人と使えない人がいるのか、あるいは使える状況と使えない状況があるのかはわかっていません。
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
xccov-to-sonarqube-generic.sh doesnt support code coverage for me
自作 fastlane action での対応
対応策として、自作の fastlane action を用意し、xccov-to-sonarqube-generic.sh と同等の処理をさせたうえで、ファイルパスが相対パスになるようにしました。ちなみに、独自の fastlane action の作成方法は次のドキュメントに書かれています。
Create Your Own Action - fastlane docs
xccov-to-sonarqube-generic.sh を改造するのではなく独自の fastlane action を作ることにした理由は下記のとおりです。
- パスの文字列操作をシェルスクリプトで頑張るのが難しかったため (Ruby などを用いたほうが楽)
- もともと fastlane を導入しており、fastlane action を導入するコストが小さかったため
作成した fastlane action については、Gist の 「generic_test_coverage.rb (fastlane action)」 にて MIT ライセンスで公開しています 2)業務時間外に書いたものなので個人名義で公開しています。。
この fastlane action を使うことにより、SonarQube でもカバレッジ集計を行うことができました。
もし私と同じように SonarQube で iOS アプリのカバレッジ集計がうまくいかず困っている人がいたら、ぜひ上記 fastlane action をご利用くださいませ。