Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

はじめに

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

:app :featureA :featureB :app featueA package featureB package

Slide 7

Slide 7 text

app/build.gradle

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

DI

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Daggerで困る例

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

テスト方針

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

モジュール内のテスト

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

Test Runner

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

ワークアラウンド

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

テストメトリクス収集

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

PITのレポート

Slide 73

Slide 73 text

PITのレポート

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

まとめ

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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