Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Speaker Deck
PRO
Sign in
Sign up for free
新規アプリの単体テスト戦略 / unit_tests_strategy_of_new_app
uhooi
October 28, 2022
Programming
2
440
新規アプリの単体テスト戦略 / unit_tests_strategy_of_new_app
iOS Test Online
https://testonline.connpass.com/event/261910/
uhooi
October 28, 2022
Tweet
Share
More Decks by uhooi
See All by uhooi
SwiftPMのPlugin入門 / introduction_to_swiftpm_plugin
uhooi
2
110
リモートワークで楽しむコツ / remote_work_is_fun
uhooi
0
230
ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる。 / iosdc_japan_2022
uhooi
4
4.5k
SwiftUIで「意図」を伝える / swiftui_intention
uhooi
3
260
"What's new in Swift"の要約 / swift_5_7_summary
uhooi
1
680
PublishでWebサイトを構築してみた / generate_website_with_publish
uhooi
2
210
SwiftPMによるマルチモジュールのアプローチ 〜ウホーイ図鑑の場合〜 / multi_module_approach
uhooi
0
340
Android StudioでVimのキーマップを使う / as_vim
uhooi
0
390
2021年の振り返り / lookback_2021
uhooi
0
130
Other Decks in Programming
See All in Programming
子育てとEMと転職と
_atsushisakai
1
430
Swift Expression Macros: a practical introduction
kishikawakatsumi
2
740
PHPDocにおける配列の型定義を少し知る
shimabox
1
140
TSX First な Zero-Runtime SSG potato4d/dodai とその仕組み / owned static site generator #kyotojs
potato4d
1
490
Remote SSHで行うVS Codeリモートホスト開発とトラブルシューティング
smt7174
1
520
AWSにおける標的型Bot対策
hacomono
0
450
Writing Greener Java Applications
hollycummins
0
370
Swift Observation
shiz
4
300
PHPアプリケーションにおけるアーキテクチャメトリクスについて / Architecture Metrics in PHP Applications
isanasan
1
300
Becoming an Android Librarian (Android World Wide 2023 Jan)
skydoves
2
230
Form実装基本を学び直してみた
hyugatsukui
0
250
Swift Concurrency in GoodNotes
inamiy
4
1.4k
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
227
16k
Writing Fast Ruby
sferik
613
58k
Designing for humans not robots
tammielis
245
24k
Art, The Web, and Tiny UX
lynnandtonic
284
18k
How to Ace a Technical Interview
jacobian
270
21k
5 minutes of I Can Smell Your CMS
philhawksworth
198
18k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
500
130k
The Art of Programming - Codeland 2020
erikaheidi
36
11k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
6
850
The MySQL Ecosystem @ GitHub 2015
samlambert
240
11k
GitHub's CSS Performance
jonrohan
1020
430k
The Invisible Side of Design
smashingmag
292
48k
Transcript
新規アプリの 単体テスト戦略 2022.10.28(Fri) iOS Test Online @the_uhooi
iOS app developer @uhooi @uhooi @the_uhooi
入社前の会話 新規アプリ作って!
入社前の会話 新規アプリ作って! はい!
ウホーイ入社 ウホーイ 入社
・UI: フル SwiftUI ・リアクティブ: Combine ・非同期処理: Swift Concurrency (async/await) ・アーキテクチャ:
MVVM ・その他: SwiftPM によるマルチモジュール、KMM ※開発中なので変更される可能性が大いにあります。 新規アプリの技術選定
最初に考えた単体テストの戦略
できる限り にする 単体テストが不要な設計 最初に考えた単体テストの戦略
できる限り にする 単体テストが不要な設計 必要な にする 単体テストを書きやすい設計 最初に考えた単体テストの戦略
01 単体テストが な 設計にする 不要
アーキテクチャ(MVVM) View View Model UseCase KMM
単体テストを書く層を明文化する View View Model UseCase KMM : 単体テストを書かない : 必要に応じて単体テストを書く
: 単体テストを書く
View 層の単体テストを書かない理由 UI/UX を確認するため、 必ず から 手動でテストを行う
どうしたら View 層から単体テストをなくせる? View View Model UseCase KMM : 単体テストを書かない
: 必要に応じて単体テストを書く : 単体テストを書く
ロジックを減らせば単体テストも減らせる View View Model UseCase KMM 少なくしたい 多くする : 単体テストを書かない
: 必要に応じて単体テストを書く : 単体テストを書く View 層からロジックを なくすのが理想 ロジック
ロジックを減らすには? ロジックを減らすには?
分岐をなくせばロジックを減らせる ロジックを減らすには? 分岐 をなくす (if 文や switch 文)
View に分岐がある(Before) // Before // View 層 if viewModel.uiState.isLoading {
Text("ロード中です。") } else { Text("ロードが完了しました。") }
View から分岐をなくす(After) // After // View 層 Text(viewModel.uiState.loadingText) // ViewModel
層 var loadingText: String { isLoading ? "ロード中です。" : "ロードが完了しました。" }
View から分岐をなくす(After) // After // View 層 Text(viewModel.uiState.loadingText) // ViewModel
層 var loadingText: String { isLoading ? "ロード中です。" : "ロードが完了しました。" } View 層の分岐を ViewModel 層に寄せる
それでも View から分岐は完全にはなくせない // View 層 struct MonstersView: View {
var body: some View { if viewModel.uiState.monsters.isEmpty { EmptyMonsterListView() } else { MonsterListView(monsters: viewModel.uiState.monsters) } } }
それでも View から分岐は完全にはなくせない // View 層 struct MonstersView: View {
var body: some View { if viewModel.uiState.monsters.isEmpty { EmptyMonsterListView() } else { MonsterListView(monsters: viewModel.uiState.monsters) } } } View の出し分けなどの 分岐はなくせない
それでも View から分岐は完全にはなくせない // View 層 struct MonstersView: View {
var body: some View { if viewModel.uiState.monsters.isEmpty { EmptyMonsterListView() } else { MonsterListView(monsters: viewModel.uiState.monsters) } } } View の出し分けなどの 分岐はなくせない monsters が空のときの UI の確認が手間
そこでプレビュー そこでプレビュー
Xcode 上で SwiftUI の View を確認できる
「UI を確認するだけの手動テスト」をなくせる プレビューでは ・端末のサイズ ・ライト / ダークモード ・データの最小 / 最大値
・エラー時の View etc... 様々な状態をかんたんに作り出せる
02 単体テストを 設計にする 書きやすい
ViewModel 層以下の単体テストを書きやすくしたい View View Model UseCase KMM : 単体テストを書かない :
必要に応じて単体テストを書く : 単体テストを書く
UI フレームワークを View 層のみでインポートする View View Model UseCase KMM SwiftUI
Combine : 単体テストを書かない : 必要に応じて単体テストを書く : 単体テストを書く View 層のみで UI を完結させる
UI フレームワークを View 層のみでインポートする View View Model UseCase KMM SwiftUI
Combine : 単体テストを書かない : 必要に応じて単体テストを書く : 単体テストを書く ViewModel 層以下がロジックに集中でき、 単体テストが書きやすくなる
Task があると単体テストしにくい(Before) // Before // ViewModel 層 struct FooViewModel: ObservableObject
{ func didTapLoginButton() { Task { await login() } } }
Task があると単体テストしにくい(Before) // Before // ViewModel 層 struct FooViewModel: ObservableObject
{ func didTapLoginButton() { Task { await login() } } } ログイン処理を待たずに テストが終了してしまう
ViewModel 層のメソッドを非同期にする(After) // After // ViewModel 層 struct FooViewModel: ObservableObject
{ func didTapLoginButton() async { await login() } }
ViewModel 層のメソッドを非同期にする(After) // After // ViewModel 層 struct FooViewModel: ObservableObject
{ func didTapLoginButton() async { await login() } } 非同期にすると 並行処理もしやすくなる
Task を View 層に書く(After) // After // View 層 struct
FooView: View { // ... Task { await viewModel.didTapLoginButton() } // ... }
ちなみに…
ちなみに… まだ単体テストを書いていません これから書きます!
03 まとめ
まとめ 設計を工夫することで、 、 できる 不安定な単体テストを減らし 安定した単体テストを書きやすく
まとめ View View Model UseCase KMM UI ロジック Task 単体テストしにくい
単体テストしやすい
まとめ View View Model UseCase KMM 単体テストしにくい・しやすいものを 分離し、単体テストする層を明確にする UI ロジック
Task 単体テストしにくい 単体テストしやすい
まとめ View View Model UseCase KMM UI ロジック Task 単体テストを書かない層(View
層)は プレビューや手動テストで品質を担保する 単体テストしにくい 単体テストしやすい