Slide 1

Slide 1 text

不具合調査とTest Kazuki Chigita (chigichan24) 2024/12/12 Android Test Night

Slide 2

Slide 2 text

$whoami 名前: Kazuki Chigita (@chigichan24) お仕事: Androidアプリ開発者

Slide 3

Slide 3 text

不具合のタイムライン

Slide 4

Slide 4 text

不具合のタイムライン ↑ バグの発生!

Slide 5

Slide 5 text

不具合のタイムライン ↑ 誰かが見つける

Slide 6

Slide 6 text

不具合のタイムライン ↑ 修正する

Slide 7

Slide 7 text

不具合のタイムライン 1: 不具合を修正して正常にしたい

Slide 8

Slide 8 text

不具合のタイムライン 2: 修正までを短くしたい →不具合の検知を早くしたい

Slide 9

Slide 9 text

不具合のタイムライン 3: 類似の不具合の発生を防ぎたい

Slide 10

Slide 10 text

不具合に関するトピック 1. 不具合を修正して正常にしたい 2. 修正までを短くしたい 3. 類似の不具合の発生を防ぎたい

Slide 11

Slide 11 text

不具合に関するトピック 1. 不具合を修正して正常にしたい 2. 修正までを短くしたい 3. 類似の不具合の発生を防ぎたい

Slide 12

Slide 12 text

1: 不具合を修正して正常にしたい ● 正常な状態に修正する 🏎 Quick Fix 🛠 Fundamental Fix 🕰 Revert

Slide 13

Slide 13 text

1: 不具合を修正して正常にしたい ● 正常な状態に修正する ○ workaroundパッチをあてる (quick fix) ○ 根本的な問題から修正する (fundamental fix) ○ 問題が発生しているcommitをrevertする (revert)

Slide 14

Slide 14 text

[🏎] Workaroundパッチを当てる ● 必ず TODO コメントと後でfoundamental fixを行うための GitHub issues / チケット等を作成する

Slide 15

Slide 15 text

[🏎] Workaroundパッチを当てる ● 必ず TODO コメントと後でfoundamental fixを行うための GitHub issues / チケット等を作成する ● テストが不足しているならこのタイミングでも追加する ○ foundamental fix を行う際に修正が適当であることを、 テストをもって保証する。

Slide 16

Slide 16 text

[🛠] 根本の問題を修正する ● 調査して見つかった問題を根本から修正する ○ テストで変更の妥当性を評価する

Slide 17

Slide 17 text

[🛠] 根本の問題を修正する ● 調査して見つかった問題を根本から修正する ○ テストで変更の妥当性を評価する どうやって調査する?

Slide 18

Slide 18 text

[🛠] 根本の問題を修正する ● 調査して見つかった問題を根本から修正する ○ テストで変更の妥当性を評価する ○ E2Eテストやマニュアルテストに頼りすぎない どうやって調査する? 統計情報とユーザシナリオに着目

Slide 19

Slide 19 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている

Slide 20

Slide 20 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的

Slide 21

Slide 21 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的 よっしゃ原因特定!

Slide 22

Slide 22 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的 修正とテストはセット

Slide 23

Slide 23 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的

Slide 24

Slide 24 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的 Unit Testに追加しやすい

Slide 25

Slide 25 text

[🛠] 根本の問題を修正する ● 統計情報 ○ 例1: 特定のOSバージョンで発生している ○ 例2: 特定のバージョンで発生している ○ 例3: 特定の条件で発生ている ● ユーザシナリオ ○ (私の経験的に)コードから追うよりも、ユースケースから 考える方が根本の原因に辿り着きやすく、本質的な 改修に繋がりやすい ○ ログなどからユーザの動作を追って再現させるのも効果的 Unit Testに追加しやすい Feature Testに追加しやすい

Slide 26

Slide 26 text

[FYI] Androidにおけるテストピラミッド https://developer.android.com/training/testing/fundamentals/strategies

Slide 27

Slide 27 text

[🕰] 問題をrevertする ● 問題が発生したcommitはどこ? ○ GitHubのtag間の変更/直近のPRを眺める ○ 差分が巨大な場合には git bisect コマンドを活用する

Slide 28

Slide 28 text

[🕰] 問題をrevertする ● git bisect ○ 二分探索を用いながら、問題が発生したcommitを見つける ○ https://git-scm.com/docs/git-bisect ○ git bisect run ./bisect.sh ■ bisect.sh で、問題を検知できるテストを実行させる ■ 問題が混入した commit が特定できる

Slide 29

Slide 29 text

[tips] testのコマンドをコピーする ● bisect.sh を作成する時にはCLIを使用する

Slide 30

Slide 30 text

[tips] testのコマンドをコピーする ● bisect.sh を作成する時にはCLIを使用する $ ./gradlew :app:testDebugUnitTest --tests "com.example.sample.ExampleUnitTest" BUILD SUCCESSFUL in 1s

Slide 31

Slide 31 text

不具合に関するトピック 1. 不具合を修正して正常にしたい 2. 修正までを短くしたい 3. 類似の不具合の発生を防ぎたい

Slide 32

Slide 32 text

2: 不具合の検知を早くしたい ● anti-pattern ○ UnitTest、Feature Test、Release Candidate Test等 全てのテストを全てのPRのCIで走らせる

Slide 33

Slide 33 text

2: 不具合の検知を早くしたい ● anti-pattern ○ UnitTest、Feature Test、Release Candidate Test等 全てのテストを全てのPRのCIで走らせる ○ マージ/機能リリースまでのリードタイムが長くなる

Slide 34

Slide 34 text

2: 不具合の検知を早くしたい ● anti-pattern ○ UnitTest、Feature Test、Release Candidate Test等 全てのテストを全てのPRのCIで走らせる ○ マージ/機能リリースまでのリードタイムが長くなる ● 適切なフェーズで適切なテストを行う!

Slide 35

Slide 35 text

[再掲] Androidにおけるテストピラミッド https://developer.android.com/training/testing/fundamentals/strategies

Slide 36

Slide 36 text

2: 不具合の検知を早くしたい ● それぞれのテストでフォーカスするべきこと

Slide 37

Slide 37 text

2: 不具合の検知を早くしたい ● それぞれのテストでフォーカスするべきこと

Slide 38

Slide 38 text

2: 不具合の検知を早くしたい ● それぞれのテストを実施するタイミング・デバイス

Slide 39

Slide 39 text

2: 不具合の検知を早くしたい ● Unit Test で実装漏れを assert できるようにする

Slide 40

Slide 40 text

[tips] [example] UnitTestで実装漏れを検知する ● ある enum class に新しい要素が追加されたことを検知する enum class FooKey { A, B, C } val SPECIFIC_PURPOSE_SET: Set = setOf(FooKey.A, FooKey.B)

Slide 41

Slide 41 text

[tips] [example] UnitTestで実装漏れを検知する ● ある enum class に新しい要素が追加されたことを検知する enum class FooKey { A, B, C, D } val SPECIFIC_PURPOSE_SET: Set = setOf(FooKey.A, FooKey.B)

Slide 42

Slide 42 text

@Test fun testKeyCompleteness() { val definedKeys = SPECIFIC_PURPOSE_SET + KEYS_NOT_TO_SPECIFIC_PURPOSE_SET FooKey.entries.forEach { assertTrue(it in definedKeys) } } @Test fun testNoDuplicatedKeys() { assertEquals( SPECIFIC_PURPOSE_SET.size + KEYS_NOT_TO_SPECIFIC_PURPOSE_SET.size, FooKey.entries.size ) } companion object { private val KEYS_NOT_TO_SPECIFIC_PURPOSE_SET = setOf( FooKey.C ) }

Slide 43

Slide 43 text

[tips] [example] UnitTestで実装漏れを検知する ● (補足) 集合 S を S_1、S_2、...、S_nに分割するときに 素集合となる条件は以下2つを満たすことだから ∀ s ∈ S, ∃ i ( s ∈ S_i ) ∀ i, j, s ∈ S_i ( i ≠ j ⇒ s ∉ S_j )

Slide 44

Slide 44 text

[tips] [example] UnitTestで実装漏れを検知する ● (補足) 集合 S を S_1、S_2、...、S_nに分割するときに 素集合となる条件は以下2つを満たすことだから ∀ s ∈ S, ∃ i ( s ∈ S_i ) ∀ i, j, s ∈ S_i ( i ≠ j ⇒ s ∉ S_j ) testKeyCompletenessに対応 testNoDuplicateKeysに対応

Slide 45

Slide 45 text

不具合に関するトピック 1. 不具合を修正して正常にしたい 2. 修正までを短くしたい 3. 類似の不具合の発生を防ぎたい

Slide 46

Slide 46 text

3: 類似の問題の発生を防ぐ ● 地道にテストピラミッドを充実させていくしかない ○ これまで紹介した不具合修正とテストの追加を 継続して続ける ○ 可視化は効果的 ● クラッシュ・ANR・アプリサイズなどのAndroid Vitals トレンドを継続的に追う ○ テストをすり抜けてしまった問題についてもケアする ○ 修正の際はテストを追加する

Slide 47

Slide 47 text

まとめ ● 不具合調査もテストドリブンにできる ○ 細かなテクニックや分類分けがある ● 日々のテスト資産が、不具合発生から修正までの リードタイムを短くする ● Testing strategiesのページは必読 ○ https://developer.android.com/training/testing/fundamentals/strategies ● 細かな話は省いているので、ぜひ後ほど

Slide 48

Slide 48 text

参考 ● Testing Strategies https://developer.android.com/training/testing/fundame ntals/strategies ● Android Vitals https://developer.android.com/topic/performance/vitals

Slide 49

Slide 49 text

不具合調査とTest Thank you