Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
iOSアプリ開発における効果的なUnitTestの戦略とその実装
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
GO Inc. dev
September 28, 2023
Programming
1
1.1k
iOSアプリ開発における効果的なUnitTestの戦略とその実装
後夜祭 iOSDC Japan 2023
で発表した資料です。
GO Inc. dev
September 28, 2023
Tweet
Share
More Decks by GO Inc. dev
See All by GO Inc. dev
MySQL, PostgreSQLのオブザーバビリティをGrafanaで向上させた話
mot_techtalk
2
250
タクシー車両の位置状態情報を支えるシステムのインフラ構成
mot_techtalk
2
270
SREの視点で挑む Redis Stream 無停止移行
mot_techtalk
2
270
生成AIで社内データを整備しよう
mot_techtalk
1
230
GO Tech Talk #31 タクシーアプリ『GO』におけるNext.jsの活用
mot_techtalk
2
510
大規模基幹サーバーに gRPCを導入した過程での学び
mot_techtalk
2
52
大規模アプリのDIフレームワーク刷新戦略 ~過去最大規模の並行開発を止めずにアプリ全体に導入するまで~
mot_techtalk
1
580
GPT-5と寿司合戦を攻略する
mot_techtalk
1
130
Grafanaスタックをフル活用したオブザーバビリティ基盤の紹介
mot_techtalk
7
1.4k
Other Decks in Programming
See All in Programming
Amazon Bedrockを活用したRAGの品質管理パイプライン構築
tosuri13
4
650
SourceGeneratorのススメ
htkym
0
200
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
370
CSC307 Lecture 09
javiergs
PRO
1
830
「ブロックテーマでは再現できない」は本当か?
inc2734
0
980
HTTPプロトコル正しく理解していますか? 〜かわいい猫と共に学ぼう。ฅ^•ω•^ฅ ニャ〜
hekuchan
2
690
AI によるインシデント初動調査の自動化を行う AI インシデントコマンダーを作った話
azukiazusa1
1
730
インターン生でもAuth0で認証基盤刷新が出来るのか
taku271
0
190
【卒業研究】会話ログ分析によるユーザーごとの関心に応じた話題提案手法
momok47
0
200
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
280
AIによる開発の民主化を支える コンテキスト管理のこれまでとこれから
mulyu
3
270
Honoを使ったリモートMCPサーバでAIツールとの連携を加速させる!
tosuri13
1
180
Featured
See All Featured
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
3.9k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
2.1k
What does AI have to do with Human Rights?
axbom
PRO
0
2k
Statistics for Hackers
jakevdp
799
230k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
94
Utilizing Notion as your number one productivity tool
mfonobong
3
220
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
62
Everyday Curiosity
cassininazir
0
130
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
1
51
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
100
Music & Morning Musume
bryan
47
7.1k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Transcript
© GO Inc. iOSアプリ開発における効果的 なUnitTestの戦略とその実装 2023.09.26 開発本部 ソフトウェア開発統括部 ユーザーシステム開発部 ユーザーシステム1グループ
/ 髙橋秀宗 GO株式会社
© GO Inc. 2 自己紹介 GO株式会社 ユーザーシステム1グループ / 髙橋秀宗 2022年12月に入社。タクシーアプリ『GO』のiOSアプリ
開発を担当 趣味はエレキギター演奏 お気に入りのアンプはMarshall JCM800 @h1d3mun3
Index © GO Inc. 1. UnitTestとは 2. 単一責任原則 3. 実践UnitTest
4. まとめ 5. 参考資料 3
© GO Inc. UnitTestとは 01
© GO Inc. V字モデル 5 実装 基本設計 結合テスト 詳細設計 コンポーネントテスト
(単体テスト ・UnitTest) 要件定義 システム/受け入れ テスト 対応するテストスコープ https://shiftasia.com/ja/column/v%E5%AD%97%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%81%AF/
© GO Inc. V字モデル 6 実装 基本設計 結合テスト 詳細設計 コンポーネントテスト
(単体テスト ・UnitTest) 要件定義 システム/受け入れ テスト 対応するテストスコープ https://shiftasia.com/ja/column/v%E5%AD%97%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A8%E3%81%AF/
© GO Inc. • 詳細設計で実装したものをテストする ◦ 作ったクラスや、変更した処理など • 要件定義・基本設計レベルの観点はテストしない UnitTestのスコープ
7
© GO Inc. • ホワイトボックステスト ◦ システムの内部も考慮したテスト ◦ if式やswitch式、guard式などが動くかどうかも考慮する •
ブラックボックステスト ◦ システムの外部をテストする ◦ 入力に対して期待する出力かどうかを考慮する ホワイトボックステスト・ブラックボックステスト 8
© GO Inc. • 🙆 メリット 🙆 ◦ 高速に、何度も、正確に実施できる ◦
実施コストが低い • 🙅 デメリット🙅 ◦ 状況に応じて操作を分けるのが難しい ◦ 人間的な操作など、非規則的なテストが難しい UnitTestの特徴 9
© GO Inc. • テスト対象 ◦ 詳細設計に対応するので、実装したクラスや処理などをチェック • コスト ◦
実行コストが低いので、CI上でDailyで回すなどして、問題の早期発見に活 用する • テスト方式 ◦ 問題の早期発見を主眼にするので、クラスや処理の入力と出力を見るブラッ クボックステストを行う UnitTestの効果的な使い方 10
© GO Inc. 単一責任原則 02
© GO Inc. • モジュールはたったひとつのアクターに対して責務を負うべきである、という原 則 • アクターとは「ユーザーやステークホルダーのグループ」のこと ◦ もちろんソースコード内部の別ファイルもアクターになりうる
🎉 → これが守られていると、モジュール(≒ソースコード)を変更する理由は必ず1つに なる 単一責任原則 12
© GO Inc. 実践UnitTest 03
© GO Inc. 1. 既存のコードをアクターを単位にして分割する 2. 分割したコードの振る舞いをProtocolに抽象化しDI可能にする 3. それぞれに対してMockを利用してテストをする 既存のコードにUnitTestを適用させる
14
© GO Inc. やってみよう! • Notification構造体でアプリ内お知らせを表現 • NotificationManagerクラスが、アプリ内お知らせを管理 し、下記を行っている ◦
現在のお知らせ一覧を返却する機能 ◦ メッセージの既読処理 ◦ APIを経由したサーバーへの反映処理 15
© GO Inc. Notification構造体 struct Notification { let title: String
let isRead: Bool } 16
© GO Inc. NotificationManagerクラス class NotificationManager { func getAllUnReadNotifications() ->
[Notification] { 〜〜〜 } func markAsRead(notification: Notification, completion: @escaping (() -> Void)) { 〜〜〜 } func postApi(notification: Notification, completion: @escaping (() -> Void)) { 〜〜〜 } } 17
© GO Inc. 修正前クラス図 18
© GO Inc. 1. 既存のコードをアクターを単位にして分割する 2. 分割したコードの振る舞いをProtocolに抽象化しDI可能にする 3. それぞれに対してMockを利用してテストをする 再掲:
既存のコードにUnitTestを適用させる 19
© GO Inc. 各責務をそれぞれ別々のファイルに分割する • メッセージの既読処理 ◦ → MarkAsReadUseCase •
現在のお知らせ一覧を返却する機能 ◦ → NotificationRepository • APIを経由したサーバーへの反映処理 ◦ → NotificationServerDataStore 既存のコードをアクターを単位にして分割する 20
© GO Inc. 修正後クラス図 21
© GO Inc. 1. 既存のコードをアクターを単位にして分割する 2. 分割したコードの振る舞いをProtocolに抽象化しDI可能にする 3. それぞれに対してMockを利用してテストをする 再掲:
既存のコードにUnitTestを適用させる 22
© GO Inc. UnitTestのときにMockを作成しやすくするため、責務をProtocolに抽象化する 分割したコードの振る舞いをProtocolに抽象化しDI可能にする 23
© GO Inc. 修正後クラス図 24
© GO Inc. 1. 既存のコードをアクターを単位にして分割する 2. 分割したコードの振る舞いをProtocolに抽象化しDI可能にする 3. それぞれに対してMockを利用してテストをする 再掲:
既存のコードにUnitTestを適用させる 25
© GO Inc. UnitTestを書く 〜 MarkAsReadUseCaseImpl 26 protocol MarkAsReadUseCase {
func execute(notification: Notification, completion: @escaping (() -> Void)) } struct MarkAsReadUseCaseImpl: MarkAsReadUseCase { let notificationRepository: NotificationRepository func execute(notification: Notification, completion: @escaping (() -> Void)) { notificationRepository.store(notification: readNotification, completion: completion) } }
© GO Inc. UnitTestを書く 〜 MarkAsReadUseCaseImpl 27 MarkAsReadUseCaseImplの役割は1つ 1. RepositoryのStore関数を呼び出す
→ 上記が正しく動作することをUnitTestで確認する
© GO Inc. UnitTestを書く 〜 MarkAsReadUseCaseImpl 28 1. NotificationRepositoryのMockを作る 2.
MockをDIしてMarkAsReadUseCaseImplを初期化する 3. テスト用のNotificationを利用してmarkAsRead関数を呼び出す。 4. Repositoryの関数呼び出し回数と、取り扱っているデータが正しいことを確認 する
© GO Inc. NotificationRepositoryのMockを作る 29 struct FakeNotificationRepository: NotificationRepository { func
getAllNotification() -> [Notification] { return [] } var storeCallCount = 0 var storeArguments: Notification! func store(notification: Notification, completion: @escaping (() -> Void)) { storeCallCount += 1 storeArguments = notification completion() } }
© GO Inc. let fakeRepository = FakeNotificationRepository() execute関数のテストを書く 30
© GO Inc. let fakeRepository = FakeNotificationRepository() let subject =
MarkAsReadUseCaseImpl(notificationRepository: fakeRepository) execute関数のテストを書く 31
© GO Inc. let fakeRepository = FakeNotificationRepository() let subject =
MarkAsReadUseCaseImpl(notificationRepository: fakeRepository) let fakeNotification = Notification(title: "テストお知らせ", isRead: false) subject.execute(notification: fakeNotification, completion: { in }) execute関数のテストを書く 32
© GO Inc. let fakeRepository = FakeNotificationRepository() let subject =
MarkAsReadUseCaseImpl(notificationRepository: fakeRepository) let fakeNotification = Notification(title: "テストお知らせ", isRead: false) subject.execute(notification: fakeNotification, completion: { in }) expect(fakeRepository.storeCallCount).to(equal(1)) expect(fakeRepository.storeArguments).to(equal(fakeNotification)) execute関数のテストを書く 33
© GO Inc. UnitTestを書いたことによる副次的なメリット • アクターをベースとした責務で切り分けたので、既存コードに対して修正を行っ た際の意図せぬ副作用のリスクを低減できた 34
© GO Inc. まとめ 04
© GO Inc. まとめ 36 • UnitTestは詳細設計に対応するテストで、クラスや処理をテストする • UnitTestをCI上でDailyで回すなどして問題の早期発見に活かすと良い •
既存コードに適用する場合は、アクターという観点で既存コードを分解してから UnitTestを組む
© GO Inc. 参考資料 05
© GO Inc. まとめ 38 • V字モデルとは ◦ https://shiftasia.com/ja/column/v%E5%AD%97%E3%83%A2%E3%83 %87%E3%83%AB%E3%81%A8%E3%81%AF/
• ホワイトボックステストとは ◦ https://service.shiftinc.jp/column/4801/ • solid+cqs+dry ◦ https://speakerdeck.com/kgmyshin/solid-plus-cqs-plus-dry
文章・画像等の内容の無断転載及び複製等の行為はご遠慮ください。 © GO Inc.