Upgrade to Pro — share decks privately, control downloads, hide ads and more …

SPMマルチモジュールで テストカバレッジを取得する技法

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

SPMマルチモジュールで テストカバレッジを取得する技法

SPMマルチモジュール構成のiOSアプリでテストカバレッジを取得しようと思うと、思わぬ壁が立ちはだかって思うように収集を行うことができません。この資料では理想的なテストカバレッジを収集できる方法と、なぜそうなっているかの原因をお伝えします。

Avatar for yosshi

yosshi

May 22, 2026

More Decks by yosshi

Other Decks in Programming

Transcript

  1. © DMM マルチモジュールの動機 - コンウェイの法則 - メガベンチャーアプリで数十万行を超える膨大なコードベース - アプリの1ボトムタブごとに専門のチームがあって、独立してメンテしたい -

    機能ごとにフィーチャーチームがあり... - アーキテクチャのレイヤーでモジュールを分割し、クリーンなコードを維持 したい 組織の形に従うように、コードベースを分割したい要求がある 4
  2. © DMM SPMマルチモジュールの誕生 引用: 「Swift Package centered project - Build

    and Practice」 https://speakerdeck.com/d_date/swift-package-centered-project-build-and-practice?slide=61 8
  3. © DMM SPMマルチモジュールのおさらい - 今 - WWDC19でXcodeとSwift Package Managerが統合 -

    Swift Packageの仕組みを使ってマルチモジュールを実現 - パッケージマネージャ & マルチモジュールを同時に解決 - ついでにpbxprojのコンフリクト問題も解決し(SPM内のソースファイルは pbxprojに乗らないため)、XcodeGenも不要化 - 使い勝手が大変良く、一気に開発のメインストリームに - (※ あくまでコミュニティベースの方法論として) 9
  4. © DMM 問題の共有 - 問題ないモノリスなサンプル - pbxproj1個で管理 - Xcodeのホストターゲット/テストターゲットを利用 -

    Domain/Entity/Repository/UI/UseCaseのレイヤーが分かれている - Caluculator/AdvancedCalculationUseCase/DMMSwiftSlideという型 でロジックが実装されており、それぞれユニットテストバンドル内にテスト がある - Firebaseを外部パッケージとして導入 - コードカバレッジの収集をOn、All Targetsを指定 12
  5. © DMM 問題の共有 - SPMマルチモジュールのサンプル - Domain/UI/UseCase/Repositoryのモジュール分割 - Domainは、さらに子として Entityターゲットを持つ

    - AppMainという.libraryを公開してpbxproj側から参照 - Xcodeのユニットテストバンドルを持たない - テストコードはSwift Packageの.testTargetで DomainTests/UseCaseTests/EntityTestsを記述 - Firebaseを外部パッケージとして導入 - コードカバレッジの収集をOn、All Targetsを指定 17
  6. © DMM 問題の共有 - SPMマルチモジュール - All Targetsでカバレッジ収集すると外部パッケージも含めて全ての ターゲットのカバレッジを拾いに行ってしまう -

    テストファイルのカバレッジまで計上されてしまう - 集計対象をsome targetsにしてライブラリを渡しても、モノリスようにパー フェクトなカバレッジ集計にならず困る - テストファイルのカバレッジも計上される - .libraryから見て推移的なモジュールのカバレッジが収集されない - モジュールは集計対象として指定できない 25
  7. © DMM 原因と振る舞い - 「カバレッジ集計対象のターゲットの dependenciesとして直接指定さ れているモジュール」のファイルのコードカバレッジを拾う仕様 - “library: AppMain→

    module: Domain → module: Entity”のようなケースで は、Entityのカバレッジは拾わない。 - テストコードが詰まったテストターゲットを指定すると、テストファイル自体のカバ レッジまでピックアップしちゃう。 26
  8. © DMM 原因と振る舞い - 細かい話をちょっとだけ - Xcodeでビルドすると必ずカバレッジデータを生成する profile-coverage-mappingというオプション付きでコンパイルされる - (たぶん、Xcodeのminimapでのカバレッジ表示用)

    - 内部的にはLLVMコードカバレッジを使っており、DerivedDataには protorawというカバレッジファイルが生成されている - xcrun llvm-cov show -instr-profile=Coverage.profdata {PathToObjectFile}/Foo.o でオブジェクトファイルとカバレッジデータを突 合する - どのファイルのどのシンボルのカバレッジはどうかのデータが作れる - データはあるのに、突合だけできてない 31
  9. © DMM 解決方法の提案 提案方法: カバレッジ収集用の .testTargetを作り、全てのモジュールを配 下にフラットに持つようにして、狙って Xcodeにカバレッジ突合をさせる - 要は「テスト実行時には必ず手元に生のカバレッジデータはあるのに拾っ

    ていないだけの状態。それを拾ってくる専用のターゲットでカバレッジを見 る」 - テストターゲットはカバレッジ収集の対象にできる - .libraryは外部に本番用のビルド成果物を晒してしまうから避けたい - テストレポートの生成は必ずテスト実行より順番が後 33
  10. © DMM 解決方法の提案 - 手順 1. 全てのモジュールをフラットに持つテストターゲットを定義する 2. xctestplanのChoose Targets…で定義したターゲットを選択する

    a. Xcodeは、ここで選択したターゲットのprotorawファイルをマージしてprofdataと いうマージ後カバレッジデータを生成し突合する仕組みのため、選択は必須 (動 作検証済み) 37
  11. © DMM 解決方法の提案 - 手順 1. 全てのモジュールをフラットに持つテストターゲットを定義する 2. xctestplanのChoose Targets…で定義したターゲットを選択する

    a. Xcodeは、ここで選択したターゲットのprotorawファイルをマージしてprofdataと いうマージ後カバレッジデータを生成し突合する仕組みのため、選択は必須 (動 作検証済み) 3. xctestplanのカバレッジ収集オプションでsome targetsを選択し、定義し たカバレッジ収集用テストターゲットを渡す (ここではZ_COVERAGE) 39
  12. © DMM 1. 全てのモジュールをフラットに持つテストターゲットを定義する a. テストコードを自身が持たない集計用の特殊テストターゲットのため「テストファイ ルのカバレッジまで計上されてしまう」問題を踏まない 2. xctestplanのChoose Targets…で定義したターゲットを選択する

    a. Xcodeは、ここで選択したターゲットのprotorawファイルをマージしてprofdataと いうマージ後カバレッジデータを生成し突合する仕組みのため、選択は必須 (動 作検証済み) 3. xctestplanのカバレッジ収集オプションでsome targetsを選択し、定義し たカバレッジ収集用テストターゲットを渡す (ここではZ_COVERAGE) 41 解決方法の提案 - 手順
  13. © DMM 問題の共有 - 解決方法の応用 - この方法は任意のモジュールを組み合わせて、任意のカバレッジ計測 グループを作れる - 例えばクリーンアーキテクチャのDomain

    + UseCaseなど内側のレイヤのモ ジュールだけ集めてテストカバレッジを計測する - DBとRepositoryのテストコードだけを計測する - などなど 44
  14. © DMM 必要ないケース - .libraryの直系の子dependenciesから推移的なモジュールが一切ないシ ンプル構成の場合 - マルチライブラリ構成で、ライブラリの依存性がフラットにまとめられている場合 など -

    いくつかのライブラリをsome targetsでカバレッジ収集対象にするだけでOK (た ぶん) - マルチモジュール構成がそもそも必要ないプロジェクト - M系チップ強くてビルド時間がそんな気にならない昨今 - フィーチャーチームの分割要求などコンウェイの法則が働いていない - → 全然モノリスプロジェクトで進めて良いと思う ※ pbxprojのコンフリクトも、Xcode 15~16あたりでほぼ発生しないような改善アップデートが入ってる 47