Affected Module Detectorでコミットの影響を受けるモジュールのUnitテストのみを実行する

f:id:shoheikawano:20211013003728j:plain Photo by Kaleidico on Unsplash

タイトルの内容について紹介します。 Affected Module DetectorのREADMEの内容や、実装コードを読むことで理解できる内容の範囲のことしか書いていません。 AndroidのプロジェクトでUnitTestを実行したいというケースを想定しています。 執筆時点の情報となっているので、最新情報についてはプロジェクトのREADMEなどをご覧ください。

Affected Module Detectorとは

Dropbox社が開発しているGradle Pluginです。

github.com

最新のコミットを取得し、コミットによる影響を受けたモジュール(affected module)を検知するもの(detector)です。 具体的には影響を受けたモジュールの検知と、そのモジュールに依存したグラフまで検知できます。

何が嬉しい?

最後のコミットの影響を受けたモジュール(またはそのモジュールに依存するモジュール)を検知できると、 最後のコミットで影響を受けた可能性のあるテストのみを実行する ことが可能になります。これが実現できると、たとえばCIのテスト実行の時間を短縮できたりすることが可能になります。

利用条件

Affected Module Detectorの利用条件として、利用されるプロジェクトがGit管理されている必要があります。

利用できるオプション

Affected Module Detectorを実行する際に、どの影響範囲までを検知するか指定するオプションが用意されています。

  • Changed Projects: These are projects which had files changed within them – enabled with -Paffected_module_detector.changedProjects)
    • →変更されたプロジェクト
  • Dependent Projects: These are projects which are dependent on projects which had changes within them – enabled with -Paffected_module_detector.dependentProjects)
    • → 変更されたプロジェクトに依存するプロジェクト
  • All Affected Projects: This is the union of Changed Projects and Dependent Projects (this is the default configuration)
    • → 変更されたプロジェクト+変更されたプロジェクトに依存するプロジェクト

プロジェクトのREADMEには、例えばPRが出たことをフックにchanged Projectsのテストを実行、PRがマージされたことをフックにAll Affected Projectsのテストを実行する、などができることが紹介されています。

使ってみる

セットアップ

READMEにある通りにセットアップをします

まずはrootのbuild.gradleに以下のような内容を追記します

buildscript {
  repositories {
    maven()
  }
  dependencies {
    classpath "com.dropbox.affectedmoduledetector:affectedmoduledetector:<LATEST_VERSION>"
  }
}

apply plugin: "com.dropbox.affectedmoduledetector"

affectedModuleDetector {
    baseDir = "${project.rootDir}"
//    logFilename = "output.log"
//    logFolder = "${project.rootDir}/output"
    excludedModules = [
        "sample-util"
    ]
}

affectedModuleDetector { } の中で設定を行います。

ローカルで正しくテストが実行されているかを確認するには logFilenamelogFolder を指定してください。コマンド実行時にどのモジュールが検知されたかなどのログを残してくれます。

excludedModules には検知対象から除外したいモジュールを指定します。適切に指定することで検知処理の時間が短くなると予想しています。(実際に計測などはしていないです)

そしてテストが存在する各モジュールのbuild.gradleに以下を追記します。

affectedTestConfiguration {
  jvmTestTask = "testDebugUnitTest"
}

この記述のみを別のbuild.gradleに切り出して apply を使って適用するようにしています。

コマンドを実行する

以下のコマンドで、detector enableを指定してdetectorを有効にしてテストを実行します。

./gradlew runAffectedUnitTests -Paffected_module_detector.enable

セットアップ後に上記コマンドをローカルで実行すると、一度目はすべてのテストが実行され、そのまま二度目を実行するとスキップされることが確認できました。

感想など

正確な計測などできていないですが、Affected Module Detectorを使って影響ないテストについてはスキップできているため、いくらかCIのテスト時間短縮に貢献してくれています。そこについては便利だなと思っています。

執筆時点ではjvmTestTask についての設定の記述がREADMEになかったため、探すのに時間がかかりました。(Pluginのコードを読みに行ってこれかな?と思って動かしてみたら動いたというラッキーパンチです。)

test coverageツールとの連携まわりがうまくいくかどうかまだ確認できていないため、もし知見のある優しい方いたら教えてもらえたら嬉しいです。 こちらは今後の自分のTODOとなっています。

この記事の内容について間違っている箇所などありましたら、ご指摘いただけたら幸いです🙏

雑ですが、以上です〜〜ズサーッε=ε=ε=c⌒っ゚Д゚)っ