はじめに
こんにちは。STORES 決済 でAndroidエンジニアをしている id:n-seki です。 最近は気温の乱高下が激しく、寒暖差で体がバグりそうですね。
さて、今日はUnitTest合宿の話をしようと思います。
UnitTest合宿とは......?
はい、そうですよね。突然「合宿」と言われても戸惑うと思います。 私の提案を聞いたチームメンバーも同じ気持ちだったかもしれません。
私たち決済AndroidチームのメンバーはそれぞれがUnitTestについて課題感を持っていました。
- UnitTestをあまり書いたことがないので、いざ書こうとすると何をテストすればよいか悩んでしまう
- UnitTestを書きたい/書いたほうが良いという気持ちはあるが、どこにテストを書くべきなのか悩んでしまう
- 既存UnitTestを参考にテストを書いているが、もっとよいテストの書き方はないのだろうか
みなさんも一度は遭遇したことのある悩みではないでしょうか。
これらのお悩みを(ある程度)解消し、チームのUnitTest力(ゆにっと・てすと・ちから)を向上させるためには次の取り組みが必要そうだと感じました。
- UnitTestの基礎的な関連知識のインプット
- 良いUnitTestに関するインプット/考える機会の提供
- チーム内でのUnitTest実装方針、設計の決定と明文化
- UnitTestを書きまくる(実践)
これら一連の学習・実践・議論をパッケージ化して複数回実施した勉強のことを、チーム内で「UnitTest合宿」と呼称し、楽しみながら取り組みました。 つまり「UnitTest合宿」とは、山奥の隔離された宿泊施設で昼夜問わずUnitTestを書き続ける鬼のUnitTest特訓、ではなく、チーム内勉強会のことでした。安心ですね。
あらためて、今日はこの「UnitTest合宿」の話をしようと思います。
合宿の背景
UnitTestを書いてテストカバレッジが上昇するのは素晴らしいことです。 しかし単にそれだけでは、我々のプロダクトを使ってくれているオーナーさんのためにはなりませんよね。機能が増えたり、出来ることが増えるわけではないので。
チームメンバー全員の時間を使ってまでUnitTest力を向上させたかったのは、中長期的な思惑があってのことでした。
つまり、「良いUnitTest」ひいては「良い設計」を学んで実践することで、これからの STORES 決済 アプリをより「品質が高く」「変更に強い」プロダクトとして成長させたい、という考えがあります。
STORESという会社は数年前とは比較にならないほどの規模に成長し、オーナーさんのお商売を支援するプロダクトを多数提供しています。多くのプロダクト・機能を生み出すための高い開発効率・プロダクションコードの安定性がいままで以上に求められていると感じます。 こうした状況下でUnitTestに投資をするのは良い判断だと思い「合宿」を実施しました。
もちろん、前述したような各チームメンバーの課題感が発端にはなっているので、よいきっかけを作ってくれたチームに感謝!
合宿の内容
合宿の大雑把な内容としては以下の通りです(再掲)。
- UnitTestの基礎的な関連知識のインプット
- 良いUnitTestに関するインプット/考える機会の提供
- チーム内でのUnitTestに関するルールの明文化
- UnitTestを書きまくる(実践)
これらをもう少し詳しく紹介しようと思います。
インプット
基礎編
AndroidエンジニアのバイブルであるところのAndroid Developers公式ガイドから、テストに関わるドキュメントをピックアップして読み合わせを実施しました。 具体的には以下のページになります。
テスト戦略を考えるための3要素(Scope/Speed/Fidelity)やテスト・ダブルの概念が紹介されており、テストの全体的な基礎知識のインプットにちょうど良い教材でした。
応用編
基礎の次は応用。ということで次に「良いUnitTest」について考える時間を取りました。使わせていただいたのはこちら。
DroidKaigi 2023のtkmnzmさんの登壇資料です。
この資料がとても素晴らしく、UnitTestに関する概念的なところから実践までがコンパクトにまとっており、Androidエンジニアじゃない人でも一見の価値があると思います。 参考文献として挙げられている『単体テストの考え方/使い方』のエッセンスも詰まっているように感じます。 個人的にはこの本大好きなのですが、結構分厚く「合宿の参考図書にするには難しいよな......」と思っていたので、こちらの資料はその点でもニーズにピッタリフィットしました。
テスト・ダブルのメリット/デメリットやHumble Objectパターンについてサンプルコード付きで学べ、チームメンバーからのポシティブなフィードバックも多かったです。
実践
インプットの次はアウトプットです。ここではモブプログラミングでUnitTestを書いてみました。
具体的にはGoogle Meetを用い、私 n-seki がAndroid Studioを画面共有して、みんなでワイワイしながらUnitTestを完成させていきます。 これまでインプットしてきた内容を思い出し、自身が携わっているアプリで実現するにはどうなるのか、全員で共有・議論しながら体験できたのがとても良かったです。
例えばモブ中にパラメタライズド・テストを書いたのですが、あまり馴染みのないメンバーからは「そういうポイントで(パラメタライズド・テストが)使えるのか」という気付きもあったようで、各々収穫があった「合宿」になったようです。
これは余談ですが、STORES では GitHub Copilot Enterprise が利用できます。モブプログラミング中も有効にしていたのですが、キーを少し叩くだけでほぼ期待するテストケース実装を提案してくれたおかげで、手を動かすよりも議論に集中できました。
実は、モブプログラミングの中心にいたのはGitHub Copilotだったのかもしれません。
議論
基礎を学んで実践も(少し)経験できました。ここからは先は各自がUnitTestを書いていくぞ!あとは頼んだ! ......と言いたいところですが、合宿はもう少し続きます。
これまで決済AndroidチームにおいてはUnitTestに対する明文化されたルールが存在しませんでした。UseCaseを実装すれば何となくUnitTestもセットにしてPull Requestを出したりしているが、そもそも我々は「どこに」「どのような」UnitTestを書くべきなのか......?
このあたりを議論して明文化したのが合宿の最終日(勉強の最後の日程)でした。
まずはこれまでの合宿を振り返り学んだことを思い出した後、ルールとした方が良い項目をみんなで出し合いました。 そこから議論を発展させ、いくつかのルールを明文化し、合宿を終えました。
ルールの一部を挙げると、
- テストケースを日本語で書く(現在は英語ですが、日本語でTryしてみることに)
- UnitTestにおいて、オブジェクトの生成は一箇所にまとめる
- モックを乱用せず、Fakeまたはプロダクションコードの利用を検討する
などです。
最後に
楽しかった合宿の日々は過ぎ去り、早くも独り立ちのときがやってきました。これからは合宿で得た知識を武器に、1人でUnitTestを実装し、プロダクションコードの安定性を見つめることになります。でも大丈夫。合宿で得た知識・経験は私たちを絶対に裏切らない。テストカバレッジに惑わされることなく、品質の高いコードを生み出していこう!
......実際のところ、決済Androidチームでは毎週の定例や、毎日の夕会もありますし、チームで協力しながら良いUnitTest・良いプロダクションを生み出して行こうと思います!
以上!