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
「Chatwork」Android版アプリを 支える単体テストの現在
Search
okuzawats
December 11, 2024
Programming
0
310
「Chatwork」Android版アプリを 支える単体テストの現在
kubell.mobile #2
https://chatwork.connpass.com/event/337364/
での発表資料です。
okuzawats
December 11, 2024
Tweet
Share
More Decks by okuzawats
See All by okuzawats
Androidアプリのモジュール分割における:x:commonを考える
okuzawats
1
370
カンファレンス参加をいかに正当化するか
okuzawats
0
280
「勉強になった」で終わらせない、ストロングスタイルの勉強会
okuzawats
0
380
10年モノのAndroidアプリのコード品質を改善していく、3つの取り組み
okuzawats
0
1.3k
Androidアプリ開発におけるSonarCloudの活用
okuzawats
0
1.1k
何故、UseCaseは1メソッドなのか
okuzawats
3
2k
例外を投げるな、値を返せ
okuzawats
9
8k
GitHub ActionsでAndroidアプリのテストを回しまくってたら全プロジェクトのCI/CDが完全停止する寸前だった件
okuzawats
0
590
Kotlinのifを愛でる
okuzawats
0
610
Other Decks in Programming
See All in Programming
スタートアップの急成長を支えるプラットフォームエンジニアリングと組織戦略
sutochin26
1
5.8k
Is Xcode slowly dying out in 2025?
uetyo
1
270
XP, Testing and ninja testing
m_seki
3
250
『自分のデータだけ見せたい!』を叶える──Laravel × Casbin で複雑権限をスッキリ解きほぐす 25 分
akitotsukahara
2
640
10 Costly Database Performance Mistakes (And How To Fix Them)
andyatkinson
0
340
Webの外へ飛び出せ NativePHPが切り拓くPHPの未来
takuyakatsusa
2
560
Goで作る、開発・CI環境
sin392
0
230
レベル1の開発生産性向上に取り組む − 日々の作業の効率化・自動化を通じた改善活動
kesoji
0
220
AI時代の『改訂新版 良いコード/悪いコードで学ぶ設計入門』 / ai-good-code-bad-code
minodriven
14
5.2k
A2A プロトコルを試してみる
azukiazusa1
2
1.4k
Quand Symfony, ApiPlatform, OpenAI et LangChain s'allient pour exploiter vos PDF : de la théorie à la production…
ahmedbhs123
0
190
5つのアンチパターンから学ぶLT設計
narihara
1
170
Featured
See All Featured
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
126
53k
GitHub's CSS Performance
jonrohan
1031
460k
Navigating Team Friction
lara
187
15k
Reflections from 52 weeks, 52 projects
jeffersonlam
351
20k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
138
34k
Facilitating Awesome Meetings
lara
54
6.4k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
Writing Fast Ruby
sferik
628
62k
Mobile First: as difficult as doing things right
swwweet
223
9.7k
Designing Experiences People Love
moore
142
24k
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
16k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Transcript
「Chatwork」Android版アプリを 支える単体テストの現在 2024/12/11 kubell.mobile#2 奥澤俊樹
自己紹介 奥澤 俊樹(@okuzawats) Androidアプリエンジニア / 株式会社kubell ビジネスチャット「Chatwork」 Android版アプリを作っ ています。 髪の毛が伸びる速度が早すぎることが悩みです。
事業概要 *1 Nielsen NetView 及びNielsen Mobile NetView Customized Report 2024年4月度調べ月次利用者(MAU:Monthly
Active User)調査。 調査対象はChatwork、Microsoft Teams、Slack、LINE WORKS、Skypeを含む41サービスを株式会社kubellにて選定。 *2 2024年9月末時点。 • 国内最大級のビジネスチャット「Chatwork」を展開。 業界のパイオニアであり国内利用者数No.1*1、導入社数は60.5万社*2を突破 • 圧倒的な顧客基盤とプラットフォームを背景に、DXされた業務プロセスそのものを提供する クラウドサービス、BPaaSを展開 BPaaS (Business Process as a Service) ビジネスチャット「Chatwork」 お客様 オペレーター
「Chatwork」Android版アプリを 支える単体テストフレームワーク
「Chatwork」Android版アプリ
「Chatwork」Android版アプリ 「Chatwork」はサービス提供開始から10年が経過しており、多くの機能を提供している。 それに比例して複雑なドメイン・ビジネスのルールが存在する。 => 複雑なドメイン・ビジネスのルールに対して、仕様を明確に表す単体テストを書きた い。 ビジネスチャットを提供するアプリという性質上、頻繁に、かつ多量のデータを送受信する 必要がある。通信量やサーバー負荷を低減するために、クライアントサイドのローカルDBに 多くのデータをキャッシュして使用している。 =>
ローカルDBを使用する箇所に対して、信頼性の高い単体テストを書きたい。
「Chatwork」Android版アプリのモジュール構成(簡略版)
「Chatwork」Android版の単体テストを支えるフレームワーク パターン① - JUnit 4 - Robolectric - Truth パターン②
- Kotest - MockK - Truth - Turbine
「Chatwork」Android版アプリのモジュールごとのテストフレームワーク
パターン①:JUnit 4 + Robolectric + 他 - 依存オブジェクトをRobolectricのShadowに置き換えて、テスト対象オブジェクトの単 体テストをできるようにしている。 -
具体的には、テスト対象オブジェクトがSharedPreferenceやSQLiteへの依存を持 つ場合にこちらのパターンで単体テストを書く。 依存オブジェクトをRobolectricの Shadowに置き換える。
パターン②:Kotest + MockK + 他 - 依存オブジェクトをMockKを用いたスタブやスパイに置き換えて、テスト対象オブジェ クトの単体テストをできるようにしている。 - RobolectricのShadowが必要ない場合はこちらのパターンで単体テストを書く。
- 大部分の単体テストはこちらのパターンになる。 依存オブジェクトをMockKを用いた スタブやスパイに置き換える。
各パターンのメリット・デメリット JUnit 4 + Robolectric + 他 Kotest + MockK
+ 他 メリット エミュレータを用いずに、本来は端 末とのインタラクションが必要な処 理の単体テストを、信頼性高く書く ことができる。 Spec形式でテストケースを書くことで、 期待挙動・仕様が明確になる。 コンテキストを分けて、階層的にテスト ケースを書くことができる。 デメリット JUnit 4を用いている場合、一般的に モダンとされるテストコードの書き 方ができない場合がある。 特にKotestの学習コストが高い。 テストコードの書き方に自由度があり、 様々な書き方が混在してしまう。 テストダブルを多用することで単体テスト の信頼性を下げてしまう可能性がある。
単体テストのフレームワーク決定までの経緯 - 元々、JUnit 4で書かれた単体テストとKotestで書かれた単体テストが混在しており、 「どちらを使うべきかわからない」という意見があった。 - 保守・学習コストの観点から、ひとつのフレームワークに統一できることが好ましい。 - 「Spec形式でテストを書きたい、コンテキストごとにテストケースを階層化した い」(=
Kotestを使いたい)という要望あった。 - 機能開発チームはフルスタックなメンバー構成となっており、Spec形式に親 和性があった。 - 複雑なドメイン・ビジネスのルールに対して、仕様を明確に表すことのでき る表現力のある単体テストを書くことは確かに重要。 - 一方、KotestはRobolectricを用いることが難しいという制約があった。 - ローカルDBを使用する箇所はRobolectricを用いて信頼性の高いテストを書きた いので、そのために必須と言えるJUnit 4を使わない判断は難しかった。
単体テストのフレームワーク決定までの経緯 - 「Robolectricが必要な場合はJUnit 4 を、それ以外の場合はKotestを使用す る」という内容のアーキテクチャデシ ジョンレコード(ADR)を書き、メン バーの承認を得て、意思決定・意思統一 を行なった。 -
何故JUnit 4が必要なのか、何故 Kotestが必要なのか、意思決定の 記録を残した。
単体テストのフレームワーク決定までの経緯 - ADR承認後、ADRでの決定に従うように既存のテストコードを書き換えた。 - Robolectricが必要な単体テストはJUnit 4 + Robolectricで、Robolectricが必要 ない単体テストはKotest +
MockKで書くように統一した。 - 元々あった「どちらのフレームワークを使うべきかわからない」という課題につい ては、ADRで方針を明示したこと、既存コードをADRに従って修正したことで解消 できた。
JUnit 4とKotestを使い分けることで得られたこと メリット: - Robolectricを用いることによるデータ層の単体テストの信頼性向上 - Spec形式で単体テストを書くことによる単体テストによる仕様明確化の効果 - 特にドメイン層やViewModelの単体テストで効果大 -
新規メンバーから「期待挙動・仕様がわかりやすかった」とのコメント有 デメリット: - 複数のテストフレームワークを使用していることによる保守コスト・学習コストの増加 - Kotestのテストコードの書き方が統一されていないことによる、テストコードの可読性 ・保守性の低下 - テストコードが書かれた時期、書いたメンバーによって書き方に差がある。
テストピラミッドの観点から考える
テストピラミッドの観点から考える テストピラミッドの観点からは、現状統合テストが足りていない。 理想とされるテストピラミッド 現状のテストピラミッド
テストピラミッドの観点から考える E2Eテスト - 今年から自動化されたE2Eテストにも取り組んでいる。 - アドベントカレンダー見てね! - E2Eテストの導入当初に想定したテストシナリオについて、既に自動化されたテストが 存在する。 統合テスト
- 統合テストについては一部存在するものの、十分な取り組みを行うことができていない ため、今後の課題であると認識している。 - 統合テストの目的設定と、統合テストで何をテストするか?の整理は必要。 - E2Eテストを小さく保つため、E2Eテストの一部のテストシナリオを統合テス トで担保する、ということはあり得る。
まとめ
まとめ - JUnit 4 + Robolectric + 他、Kotest + MockK
+ 他を使い分けることによって、テス ト対象オブジェクトの特性に応じて最適な単体テストを書くことができるようになっ た。 - Kotestで(再び)Robolectricが動くようになると、テストフレームワークが統一 できて嬉しい。 - Kotestは様々なテストコードの書き方ができるため、テストコードが書かれた時期や書 いたメンバーによってテストコードの書き味に差異が出てしまった。 - この点はチームでも課題だと認識しており、今後改善していきたい。 - テストピラミッドの観点を取り入れて、E2Eテスト・統合テスト・単体テストそれぞれ の目的と内容を再定義していくことが、今後は必要になるかもしれない。