マルチモジュールなプロジェクトでテストはどう変わるか? / How change testing in modular architecture

7867fe52a9be4257508a516d4df61578?s=47 tkmnzm
February 07, 2019

マルチモジュールなプロジェクトでテストはどう変わるか? / How change testing in modular architecture

7867fe52a9be4257508a516d4df61578?s=128

tkmnzm

February 07, 2019
Tweet

Transcript

  1. マルチモジュールな プロジェクトで テストはどう変わるか? Nozomi Takuma 2019/2/7 DroidKaigi2019

  2. 自己紹介 Nozomi Takuma SWET@DeNA所属 (2018/3~) Androidとテストが好き

  3. はじめに

  4. マルチモジュールって? :app :featureA :featureB アプリの実装を 複数のモジュールに 分割する

  5. :app featueA package featureB package これまでのアーキテクチャ appモジュール内に 実装をまとめた モノリシックな構成

  6. :app :featureA :featureB :app featueA package featureB package

  7. app/build.gradle

  8. なぜマルチモジュールにするのか? • 差分ビルドによるビルド時間短縮のため • App BundleやInstant App対応のため • それぞれの機能を分離させることで機能 間の独立性を保つため

  9. マルチモジュールプロジェクトの テストで変わらないこと • テストを書くこと • テストの書きかた

  10. マルチモジュールプロジェクトの テストで変わる3つのポイント 1. DI 2. テスト方針 3. メトリクス収集

  11. DI

  12. DI(Dependency Injection)って? • コンポーネントの依存を外から渡せる ようにする • テストをしやすくするためのパターン として利用される • DI

    LibraryとしてDaggerが有名
  13. マルチモジュールでのDI悩みポイント 1. モジュール間の依存関係を クリーンに保ちたい 2. 依存の定義をモジュール内で完結 させたい

  14. モジュール間の依存をクリーンに保ちたい app module feature module 依存解決にapp module内のクラスが 必要な場合、循環参照が発生する可能性がある

  15. Daggerで困る例

  16. Daggerで困る例 feature module内の Activity app module内の Application

  17. 依存の定義をモジュール内で完結させたい • どのように依存が解決されるかの定義は モジュール内で完結できるとうれしい • DaggerでいうとModuleクラスの定義 など

  18. マルチモジュールでのDI DIのやりかたやDIライブラリの使い方に よっては、前述の悩みポイントに対応する ため書き方や構成の変更が必要になる

  19. 話しきれないので... 『マルチモジュールプロジェクトでの Dagger2を用いたDependency Injection』 02/07 11:20 - 11:50@Hall A

  20. サンプル • Dagger-Android https://github.com/tkmnzm/MultiModulePlayground

  21. テスト方針

  22. モジュール化によって得られるメリット • ビルド時間短縮による開発速度向上 • 意味のあるまとまりに分けることによって 他モジュールへの影響範囲が小さくなる

  23. 動作確認もモジュール内で完結 できるようにしたらどうだろう? モジュール化のメリットを得るために

  24. モジュール内で動作確認を完結できると • 各モジュールの動作確認をするために 全体のapkをビルドしなくてよい • 動作確認済みのモジュールを使用する ことで、モジュールを結合したときの 動作確認が楽になる

  25. モジュール内でどんな動作確認が できていたら嬉しいか? テスト方針を考える問いかけ

  26. とあるモノリシックなプロジェクトの例 Presenter UseCase Repository 呼び出していることを 意味する矢印

  27. とあるモノリシックなプロジェクトの例 Presenter UseCase Repository ユニット テスト

  28. • レイヤー内の代表的なクラスのユニット テストは充実していた(UseCase,Repo など) • しかし上記以外の実装もたくさんあり テストが手薄なところもあった とあるモノリシックなプロジェクトの例

  29. • このモジュールの動作確認はいまある テストだけだと足りない気がする... • この例の場合、UI部分やITテストが 不足していた モジュールとして分割してみた時

  30. • まとまりの責務を考えるきっかけ • モノリシックなプロジェクトではレイ ヤーごとにどうテストするかを考える ことが多かったが、モジュール毎とい う新しい視点が生まれる モジュールとして切り出す

  31. • モジュール内のテスト • モジュールをまたいだテスト モジュールのテスト方針を考えてみよう

  32. モジュール内のテスト

  33. モジュールの設計時に考えたいこと • モジュールの責務 • モジュールのテスト範囲

  34. 自動テストの手段はいろいろ ITテスト ユニット テスト UIテスト

  35. 例えばこんなモジュール① Utility Utility Utility

  36. 例えばこんなモジュール① Utility Utility Utility ユニット テスト

  37. 例えばこんなモジュール② Logic Logic Android PF

  38. Logic Logic Android PF 例えばこんなモジュール② ユニット テスト IT テスト

  39. Logic Logic Android PF 例えばこんなモジュール② IT テスト

  40. 例えばこんなモジュール③ Activity Logic Android PF

  41. Activity Logic Android PF 例えばこんなモジュール③ UI テスト IT テスト

  42. Activity Logic Android PF UI テスト 例えばこんなモジュール③

  43. 方針考えたけど何から手を付ける? ユニットテストで十分なところは ユニットテストからはじめる ユニット テスト

  44. 導入の容易さ ITテスト ユニット テスト UIテスト

  45. FBサイクルの速さ ITテスト ユニット テスト UIテスト

  46. ITテスト・UIテスト ユニットテストでは動作確認として 不足している部分に追加していく しかし、自分自身はAndroid PFが絡むテ ストは避けがちだった

  47. ITテスト・UIテスト ユニットテストでは動作確認として 不足している部分に追加していく しかし、自分自身はAndroid PFが絡むテ ストは避けがちだった AndroidのAPIが絡むテストも導入しやすくなるよう 環境が変わりつつある

  48. Project Nitrogen 実行環境の差分を統一した • API • Test Runner

  49. API Robolectric上でも実機上でも実行可能

  50. Test Runner

  51. Project Nitrogenに期待すること • ローカルでのテスト: Robolectric上で素早く実行 • CIでのテスト: 実機やVirtual Device上など fidelity(忠実度)の高い環境で実行

  52. None
  53. 現状は... • Robolectricで実行するには: src/testにテストコードを配置 • Deviceで実行するには: src/androidTestにテストコードを配置

  54. ワークアラウンド

  55. モジュール内のテストまとめ • モジュールの責務とテスト範囲を考える • まずはユニットテストからはじめる • ITテストやUIテストはつまづきがち だが、導入しやすい環境が整いつつある

  56. もしテストを書く時間がなくても • テスタビリティは意識して実装したい • いざテストを書こうとしたときにテスト が書きにくい状態になっていると まずはリファクタリングが必要になる

  57. モジュールをまたいだテスト

  58. テストの方針 Module B Module A Module A Module B モジュールごとにテスト

    結合してテスト
  59. モジュールごとにテスト FeatureBをモック化

  60. 結合してテスト 実インスタンスや Spyを使用

  61. モジュールをまたぐといっても • テストの書き方はいままでと変わらない • 他モジュールへの依存を外から渡すように していれば、これまでどおりテストダブル が使用できる

  62. どれを選択する? • ケース・バイ・ケース • 自分のプロダクトではどんな不具合が起き やすいか?(単体でも拾える?結合しない とだめ?)というのは判断に使えそう

  63. テストメトリクス収集

  64. テストメトリクス Android開発でよく 使われているのは • JUnit実行結果 • Jacoco

  65. マルチモジュールでのテストメトリクス収集 各モジュールのレポートをまとめて 見たい場合、結果のマージが必要

  66. Jacocoについては... 『Spek2+MockK+JaCoCoでイケてるUnit Test環境を手に入れろ!』 02/08 11:20-11:50@Room 1

  67. PIT Java、その他JVM言語用MutationTesting ツール http://pitest.org/

  68. Mutation Testing • プロダクトコードを機械的に変更し、 変更されたコードに対してテストを実行 • テストが失敗するかを確認することで、 テストコードが振る舞いの変更を検知 できるかチェックする

  69. 例: Conditionals Boundary Mutator if (hoge <= 5) { //

    do something } if (hoge < 5) { // do something } hogeが5のときの 振る舞いが Mutatorによって変更
  70. 例: Conditionals Boundary Mutator if (hoge <= 5) { //

    do something } if (hoge < 5) { // do something } hogeが5のときの 振る舞いが Mutatorによって変更 hogeが5のときの テストが正しく書かれて いれば失敗するはず...
  71. 例: Conditionals Boundary Mutator テストを実行し... • テストが失敗する: OK • テストが成功する:

    NG 境界値チェックなど、不足しているテストケースを 見つける手助けをしてくれる
  72. PITのレポート

  73. PITのレポート

  74. PITのうれしいところ • Mutation Coverageと Line Coverageが見られる • Android用GradlePluginがある • Kotlinのサポートが進んでいる

  75. 実行結果のマージ: マージ処理抜粋

  76. 実行結果のマージ: PIT設定抜粋

  77. サンプル https://github.com/tkmnzm/MultiModulePlayground • PIT導入 • PITレポートのマージ

  78. まとめ

  79. 1. DI 2. テスト方針 3. メトリクス収集 まとめ • DIのやりかたによっては 書き方や構成の変更が必要

    • 詳細はその他のDI関連 セッションで!
  80. 1. DI 2. テスト方針 3. メトリクス収集 まとめ • モジュール設計時に モジュールのテスト方針を

    考えてみる • IT・UIテストもハードルが 下がりつつある
  81. 1. DI 2. テスト方針 3. メトリクス収集 まとめ • 各モジュールの結果を マージする必要がある

    • 不足しているテストケース を見つけてくれるPITを ご紹介
  82. ご清聴ありがとうございました