$30 off During Our Annual Pro Sale. View Details »

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

tkmnzm
February 07, 2019

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

tkmnzm

February 07, 2019
Tweet

More Decks by tkmnzm

Other Decks in Programming

Transcript

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

    View Slide

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

    View Slide

  3. はじめに

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  7. app/build.gradle

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  11. DI

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  15. Daggerで困る例

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  21. テスト方針

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  50. Test Runner

    View Slide

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

    View Slide

  52. View Slide

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

    View Slide

  54. ワークアラウンド

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  71. 例: Conditionals Boundary Mutator
    テストを実行し...
    ● テストが失敗する: OK
    ● テストが成功する: NG
    境界値チェックなど、不足しているテストケースを
    見つける手助けをしてくれる

    View Slide

  72. PITのレポート

    View Slide

  73. PITのレポート

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  78. まとめ

    View Slide

  79. 1. DI
    2. テスト方針
    3. メトリクス収集
    まとめ
    ● DIのやりかたによっては
    書き方や構成の変更が必要
    ● 詳細はその他のDI関連
    セッションで!

    View Slide

  80. 1. DI
    2. テスト方針
    3. メトリクス収集
    まとめ
    ● モジュール設計時に
    モジュールのテスト方針を
    考えてみる
    ● IT・UIテストもハードルが
    下がりつつある

    View Slide

  81. 1. DI
    2. テスト方針
    3. メトリクス収集
    まとめ
    ● 各モジュールの結果を
    マージする必要がある
    ● 不足しているテストケース
    を見つけてくれるPITを
    ご紹介

    View Slide

  82. ご清聴ありがとうございました

    View Slide