Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Kotlin/Androidでテスト駆動開発をはじめよう
Search
hiro
June 23, 2024
Programming
1.2k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Kotlin/Androidでテスト駆動開発をはじめよう
magicpodさん主催のイベント「モバイルアプリ開発における良いテストコードの考え方」のセッションスライドです。
hiro
June 23, 2024
More Decks by hiro
See All by hiro
KoogではじめるAIエージェント開発
hiroaki404
2
3.6k
Compose Navigation実装の見通しを良くする
hiroaki404
0
420
Compose UIテストを使った統合テスト
hiroaki404
0
450
Other Decks in Programming
See All in Programming
変化を抱擁するドキュメントの作り方 - ビジネスルール駆動開発がもたらす、コードとの新しい関係
ioki
2
210
アクセシビリティから考える情報設計
high_g_engineer
0
380
Jetpack Compose メカニズム
skydoves
0
440
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2k
LL言語やWebフレームワークのPostgreSQL対応 〜DBの機能がユーザーに届くまで〜
kentaroutakeda
1
150
SREの越境 / SRE Collaboration
y0hgi
2
230
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
AHC070解法紹介
eijirou
0
120
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
220
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
140
AWS DevOps Agentで インシデント対応をAIに任せたい
honmarkhunt
7
3k
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
560
Featured
See All Featured
Optimizing for Happiness
mojombo
378
71k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
76k
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
340
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
320
技術選定の審美眼(2025年版) / Understanding the Spiral of Technologies 2025 edition
twada
PRO
120
120k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
A Tale of Four Properties
chriscoyier
163
24k
The Cost Of JavaScript in 2023
addyosmani
55
10k
Accessibility Awareness
sabderemane
1
210
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
63
46k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Transcript
MAZDA MOTOR CORPORATION Confidential 納庄 宏明 マツダ株式会社 Kotlin/Androidでテスト駆動開発をはじめよう モバイルアプリ開発における良いテストコードの考え⽅ 2024/6/24
⾃⼰紹介 •納庄 宏明 Nosho Hiroaki •マツダ株式会社, Android Engineer 2022〜 •Mazda開発チームについて
•ITチームは東京本社・広島本社の2拠点+リモート •中途採⽤に積極的 •Mazdaアプリの紹介 •MyMazda: コネクテッドサービスアプリ など⾃動⾞関係のiOS/Androidアプリを公開
本セッションの⽬的 •TDDを⼀つの⼿段として提⽰する •Androidの良いユニットテストを考える
参考⽂献・リンク 書籍 • 『テスト駆動開発』KentBeck著 オーム社 • 『Googleのソフトウェアエンジニアリング』 オライリー・ジャパン • 『単体テストの考え⽅/使い⽅』
Vladimir Khorikov著 マイナビ Webリンク • Android developer guide • アプリ アーキテクチャ https://developer.android.com/topic/architecture/intro • Android でアプリをテストする https://developer.android.com/training/testing • サンプル • Now in Android、architecture-samplesなどの公式のサンプル 注意点 • TDDやテストには⾊々な考え⽅があります。個⼈的な⾒解をまとめたものです。 スライド 補⾜
TDDとは?
ある開発現場の悩み テストがない そもそもテスト作りづらい 機能作らなきゃ、リファクタリン グしなきゃ、で頭がいっぱい TDD テストがある テストが作りやすい やるべきことに集中でき、迷いが ない
TDDとは? •テスト駆動開発(Test-Driven Development 略してTDD) • テスト駆動開発 (てすとくどうかいはつ、英: test-driven development; TDD)
とは、プログラム開発⼿法の ⼀種で、プログラムに必要な各機能について、最初にテストを書き(これをテストファーストと⾔う) 、そのテストが動作する必要最低限な実装をとりあえず⾏なった後、コードを洗練させる、という短い ⼯程を繰り返すスタイルである。 • Wikipedia「テスト駆動開発」https://ja.wikipedia.org/wiki/テスト駆動開発 •要は先にテストを書いてから実装することが⼤きな特徴の開発 スタイル •統合テストもTDDで⾏い、構造化することも可能
•テストすることが開発サイクルに組み込まれる •やるべきことに注⼒でき、開発が効率化される •これから開発するコードの仕様を作成できる •プロダクションコードがテストしやすい形になる •など TDDのメリット テストがある テストが作りやすい やるべきことに集中でき、迷いが ない
TDDの実践
TDDで開発する機能 • 野⿃図鑑アプリ • ViewModelの実装とユニットテスト • Googleのアーキテキチャガイドに沿ったもの • Repositoryを通してリモートのAPIからデータを取得 •
機能:野⿃の⼀覧を取得する (UIやデータソースのプロダクションコードは作りません) github: https://github.com/hiroaki404/tddKotlin (追加の実例もあります)
Red Green Refactoring •Red •失敗するテストを書く •Green •テストを通るようにプロダクションコー ドを書く。テストを通すことだけに集中 する •Refactoring
•テストを通すために発⽣した重複を除去 する。コードを整える Red Green Refactor
Red
red-green-refactoring 失敗するテストを書く プロダクションコードを書かずに、 テストから書く class ExampleViewModelTest { }
プロダクションコードを書かずに、 テストから書く red-green-refactoring 失敗するテストを書く class ExampleViewModelTest { private lateinit var
exampleViewModel: ExampleViewModel @Before fun setup() { exampleViewModel = ExampleViewModel() } }
class ExampleViewModelTest { private lateinit var exampleViewModel: ExampleViewModel @Before fun
setup() { exampleViewModel = ExampleViewModel() } @Test fun `⿃の⼀覧を取得できる`() = runTest { // Given // When // Then } } red-green-refactoring 失敗するテストを書く Given-When-Then構⽂ Given(前提条件)-When(操作)-Then(結果) の形式によりテストコードの可読性を ⾼める プロダクションコードを書かずに、 テストから書く
class ExampleViewModelTest { private lateinit var exampleViewModel: ExampleViewModel @Before fun
setup() { exampleViewModel = ExampleViewModel() } @Test fun `⿃の⼀覧を取得できる`() = runTest { // Given // When // Then assertEquals( ExampleUiState( birds = listOf( suzume, tsubame, magamo ) ), exampleViewModel.uiState.value ) } } red-green-refactoring 失敗するテストを書く 前提条件って何? 野⿃取得が取得される前の、 ローディング状態 初期状態のテストもあるとよい が、今回はパス Given-When-Then構⽂ Given(前提条件)-When(操作)-Then(結果) の形式によりテストコードの可読性を ⾼める プロダクションコードを書かずに、 テストから書く
red-green-refactoring 失敗するテストを書く class ExampleViewModelTest { private lateinit var exampleViewModel: ExampleViewModel
@Before fun setup() { exampleViewModel = ExampleViewModel() } @Test fun `⿃の⼀覧を取得できる`() = runTest { // Given // When exampleViewModel.refresh() // Then assertEquals( ExampleUiState( birds = listOf( suzume, tsubame, magamo ) ), exampleViewModel.uiState.value ) } }
class ExampleViewModelTest { private lateinit var exampleViewModel: ExampleViewModel @Before fun
setup() { exampleViewModel = ExampleViewModel() } @Test fun `⿃の⼀覧を取得できる`() = runTest { // Given // When exampleViewModel.refresh() // Then assertEquals( ExampleUiState( birds = listOf( suzume, tsubame, magamo ) ), exampleViewModel.uiState.value ) } } Redを確認しました。 これが第⼀歩です red-green-refactoring 失敗するテストを書く class ExampleViewModelTest { private lateinit var exampleViewModel: ExampleViewModel @Before fun setup() { exampleViewModel = ExampleViewModel() } @Test fun `⿃の⼀覧を取得できる`() = runTest { // Given // When exampleViewModel.refresh() // Then assertEquals( ExampleUiState( birds = listOf( suzume, tsubame, magamo ) ), exampleViewModel.uiState.value ) } }
Green
class ExampleViewModel: ViewModel() { private val _uiState = MutableStateFlow(ExampleUiState()) val
uiState: StateFlow<ExampleUiState> = _uiState.asStateFlow() fun refresh() { } } red-green-refactoring テストを通るようにプロ ダクションコードを書く Green
class ExampleViewModel: ViewModel() { private val _uiState = MutableStateFlow(ExampleUiState()) val
uiState: StateFlow<ExampleUiState> = _uiState.asStateFlow() fun refresh() { viewModelScope.launch { _uiState.update { it.copy( birds = listOf(suzume, tsubame, magamo) ) } } } } red-green-refactoring テストを通るようにプロ ダクションコードを書く Green この時点では罪を犯し とにかく最速でGreenを⽬指す
Refactoring
Refactoring class ExampleViewModel: ViewModel() { private val _uiState = MutableStateFlow(ExampleUiState())
val uiState: StateFlow<ExampleUiState> = _uiState.asStateFlow() fun refresh() { viewModelScope.launch { _uiState.update { it.copy( birds = listOf(suzume, tsubame, magamo) ) } } } } red-green-refactoring テストを通すために発⽣ した重複を除去する。 コードを整える テストのexpectとrefresh内部に 重複があったので、Repositoryか ら取得するように変更
Refactoring @HiltViewModel class ExampleViewModel @Inject constructor( private val repository: ExampleRepository
) : ViewModel() { private val _uiState = MutableStateFlow(ExampleUiState()) val uiState: StateFlow<ExampleUiState> = _uiState.asStateFlow() fun refresh() { viewModelScope.launch { val birds = repository.getBirds() _uiState.update { it.copy( birds = birds ) } } } } red-green-refactoring テストを通すために発⽣ した重複を除去する。 コードを整える テストのexpectとrefresh内部に 重複があったので、Repositoryか ら取得するように変更 テストからはフェイクを使う ※フェイクとは、下記のような ⾃作のテストダブル
TDDのメリット
TDDのメリット •テストすることが開発サイクルに組み込まれる •やるべきことに注⼒でき、開発が効率化される •これから開発するコードの仕様を作成できる •プロダクションコードがテストしやすい形になる •など •やるべきことに注⼒でき、開発が効率化される •これから開発するコードの仕様を作成できる 作業を細かいステッ プに分割して集中
⾃信を持ってリファ クタリング コードを書く前に 仕様を整理できる テストがある テストが作りやすい やるべきことに集中でき、迷いが ない
TDDのメリット •テストすることが開発サイクルに組み込まれる •やるべきことに注⼒でき、開発が効率化される •これから開発するコードの仕様を作成できる •プロダクションコードがテストしやすい形になる •など テストがある テストが作りやすい やるべきことに集中でき、迷いが ない
TDDをやらなかった場合、動けば良いで書いてしまいがち TDDでやらなくても慣れで書けるようになるが、意識が⾼まる initブロックを使うと 初期状態をテストしづらい Repositoryを直接呼び出してしまう フェイクを差し込めるようにする べき NG例です
ViewModelをテスタブルにしよう •状態の公開を読み取り専⽤のuiStateだけに限る •テストではuiStateをアサートすることに注⼒できる •Context、Activity、Fragmentに依存しない •Interfaceに依存し、フェイクを使えるようにしよう •DIのHiltを使う •複雑になってきたらUseCase等に処理を分割する
Flowを使った形に直そう •Flowを使うとオペレータが豊富に使えたり、制御もテストもし やすい
Flowはどうテストするの?
Flowはどうテストするの? • Turbineがおすすめ • Flowのテストが書きやすい • suspend関数も扱いやすくなる
TDDのデメリット
TDDのデメリット •それなりに労⼒がかかる •テストを書くのが⾜かせになり、後回しにしがち ->労⼒にならないために、どうするか?
AIの⽀援を使えば楽できる • github copilotがあれば、テスト作成をラクにできる テストを書くには精度が⾼く、 コード作成の補助として使える 他に • Android Studioのcode
template機能の設定で ボイラーコードを展開する • Refactor機能などでメソッド等の作成や Interfaceの抽出の⾃動化
•TDDを実施するだけで良いユニットテストが書けるわけではない •それなりに労⼒がかかる •テストを書くのが⾜かせになり、後回しにしがち ->労⼒にならないために、どうするか? TDDのデメリット
TDDの意識外でがんばること • 明快なテストを書く。失敗したときにすぐアクションできるようにする • テストケースを眺めただけで失敗した原因がわかるとよい • 安易に共通値や共通化をしすぎない • Truthライブラリなどでアサーションの⾒通しを良くする •
モックよりフェイクを使う(Googleも推奨) • 実⾏時間、忠実度の⾯でフェイクが良く、変更にも強い • 忠実度に関して、モック<フェイク<実際のクラス • フェイクは適切にメンテする必要がある • (今回はRepositoryにフェイクを使いましたが、 実際のクラスが使えるなら使ったほうが忠実度が上がる) • TDDをやるなら依存の少ないクラスから作ると、⽤意すべきテストダブルが減る
TDDの意識外でがんばること • TDDであれば、⾼速化は特に重要 • ⼩さなステップのなかでテストをたくさん実⾏するため • マルチモジュール化、並列化 • 保守コストや忠実度、速度などとのバランスを考える •
複雑なViewModel、ドメイン、ユーティリティのテストを重視 • カバレッジにとらわれすぎないこと • 必ずしもクラスやメソッドごとにテストするわけではない • チームで作るなら、レイヤーごとに分けてルール化など • (注)安全性関わる部分など重⼤な部分は⾼いカバレッジを⽬指します • UIのリグレッション検知ならスクリーンショットテストがおすすめ • 保守コストが低い • Roborazzi 、公式のスクリーンショット • UIテストをやるなら実⾏速度と保守コストのバランスで判断する • E2Eテストは忠実度が⾼く、バグの検出⼒も⾼い • ユニットテストと補完しあう E2E 統合テスト ユニットテスト コスト 忠実性 速度 決定性
おわりに • TDDをやってどうなった? • 開発効率があがった • テストへの意識が変わる • TDDをやりづらい場合もあるので、厳密にやったり毎回必ずやる必要はない •
技術をあまり理解できていなときなど • 既存のコードがあるところなどやりやすいところからやってみましょう