Merpay & Mercoin Tech Fest 2023 は、事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知ることができるお祭りで、2023年8月22日(火)からの3日間、開催しました。セッションでは、事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介していきました。
この記事は、「1週間リリースを支えるAndroid自動テスト運用のその後」の書き起こしです。
@kenken:それでは、「1週間リリースを支えるAndroid自動テスト運用のその後」について発表します。
簡単に自己紹介をします。
@kenken:メルペイAndroidチームの@kenkenと申します。2021年5月にメルペイへ入社しました。現在はメルペイのあと払いをはじめとした、与信領域の機能開発やリグレッションテストの自動化などを担当しています。
@shinmiy:同じくメルペイAndroidチームの@shinmiyといいます。2021年12月に入社し、Androidのエンジニアとして、支払いタブやクレジットカード関連の開発、テストの自動化などを担当しています。
@kenken:それではまず、メルカリアプリの現在のリリースサイクルとリグレッションテストの自動化フローについて説明します。この内容は、2021年12月にMerpay Advent Calendarで公開された「1週間リリースを支えるAndroidテスト運用」というブログでも紹介しています。
現在、メルカリアプリでは、年末年始などを除いて基本的に毎週リリースが行われています。こちらの図は、リリースまでの流れを表しています。
まず、一番右のリリース日の4営業日前に、リリース用のブランチが作成されます。このブランチに含まれているコードが、リリースの対象となります。
従ってリリースしたいコードに関するQAがこのタイミングまでに完了し、かつメインブランチにマージされている必要があります。その後、Androidアプリ・iOSアプリともに、1営業日をかけてリグレッションテストを実施し、クリティカルな不具合がなければ、各ストアへ申請を行います。このリグレッションテストの一部をE2Eテストとして自動化しています。
現在は毎週行われているリリースですが、以前は隔週で行われていました。
当時の隔週のリリースサイクルでは、QAの完了からリリースまでに最長2週間待つ必要があるため、実装が完了した機能をお客さまに届けるまでのタイムラグが大きくなってしまう、Hotfixが必要になったときのリリース日の調整コストがかかってしまうなどの課題がありました。
そこで、現在のようにリリースサイクルを毎週に変更することが検討されました。また、Hotfixが必要になった際は、よほど大きな影響がない限りは、翌週のリリースまでに対応する方針も検討されました。
ここで判明した課題の一つが、リグレッションテストにかかる期間です。リリースサイクルが短縮されたとしても、リグレッションテストの実施内容は以前と大きく変わらないため、リリースサイクルのアップデートを実現するためには、2日にわたって行っていたリグレッションテストを1日に収める必要がありました。
この期間を短縮するために、リグレッションテストの自動化が求められるようになり、今回話す取り組みが始まりました。
参考記事:メルカリ・メルペイで行ったリリースサイクルのアップデート
このような経緯があり、メルペイではリリース前に行うリグレッションテストの一部をE2Eテストとして自動化しています。
テストコードは、Espressoというフレームワークを使って書いており、CI上で特定のラベルが付いたプルリクエストをフックしたり、夜間にE2Eテストを実行したりしています。
テスト自体はFirebase Test Labというクラウド上でテスト端末などを提供するサービスを使って、並列に実行しています。
そして、Firebase Test Labでテストした結果をTestRailというテスト管理ツールにAPIを介して記録しています。この流れでE2Eテストを実行しています。
細かい部分でもいくつか工夫をしています。CIの実行にはお金と時間がかかるので、全てのプルリクエストに対してE2Eテストを実行するのではなく、特定のラベルやコメントを付けることで、必要なテストを必要なときにだけ動かしています。
こちらの例では、GitHubのコメントに「mp-uitest-filter dashboard」とコメントすることで、dashboardというパッケージのテストコードのみが実行されるようになっています。
また、今回の発表では詳細は割愛しますが、テストユーザー作成用のuser-tkoolという社内ツールを使うことによって、特定のユーザーを使い回さずにテストを行えるようにしています。こちらは過去のブログ記事でも触れているので、興味ある方はご覧ください。
次に、リグレッションテストを自動化するまでの流れをお話しします。リグレッションテストの自動化はQAチームと連携して行っています。
パターンとしては、新しくテストケースが作成される場合と、既存機能の改善に伴い、テストケースを更新する2つのパターンがあります。いずれの場合でも、TestRailとJiraというタスク管理ツールを使ってやり取りしています。
テストの実装については、TestRailに書かれている内容をもとに行います。左から順に、QAチームがテストケースを作成・更新して、内容をTestRailに反映します。TestRailでは、テストケースの実行種別でmanualかautoを指定できるようになっており、最初はmanualを指定します。その後、Jiraチケットを作成し、該当のケースへのURLを記載します。
チケットが作成されたら、エンジニア側でチケットに記載されているTestRailのテストケースを確認して、自動化が可能か、テストケースとしてケースの粒度が適切かなどの確認を行います。
この時点で自動化が難しいと判断した場合は、該当のチケットをクローズします。自動化が可能と判断した場合は、テストケースの実装を行い、該当のチケットをクローズし、TestRailのテストケースの実行種別をmanualからautoに変更します。
リグレッションテストの結果、autoのテストケースのうち、失敗率が高かったものに関しては、QAチームがマニュアルで該当のテストを再実行します。
次に、ブログ公開から現在までの約1年半の中で変化したことについて話します。
この期間に、メルカリ・メルペイではいくつかの大きな変化が起こっています。私たちの取り組みに影響する部分としては、大きく2点あります。
メルカリでは、GroundUP Appと題したリアーキテクチャプロジェクトを2020年から続けていて、2021年の後半にリリースをしています。これは、メルカリアプリをイチから書き直したもので、コードベースを今のアーキテクチャの潮流に合った形に置き換えています。
Androidアプリとしては、UIに関する部分をJetpack Composeというライブラリに置き換えています。しかし、メルペイの機能に関するコードについては、事業成長のための機能開発・改善を優先するために、GroundUP Appプロジェクトのリリース当初は、Jetpack Composeへの移行は行っていませんでした。現在では追従するように、機能ごとに順次Jetpack Composeへの移行を行っています。
メルペイとしては、最初に支払いタブのリニューアルを行い、リニューアルのタイミングでJetpack Composeに置き換えています。支払いタブというのは、右側にある図の画面です。このあたりについても、昨年のMerpay Tech Fest 2022で、取り上げているので、よろしければご覧ください。
参考記事:【書き起こし】段階的Jetpack Compose導入〜メルペイの場合〜 – Junya Matsuyama【Merpay Tech Fest 2022】
開発体制においては、メルペイは昨年末より、「プログラム体制」をとるようになりました。
それまでは、プロジェクトと職種の2軸をもとに担当を決める「プロジェクトマトリックス体制」をとっていて、Androidチームのメンバーも、四半期ごとにさまざまなプロジェクトにアサインされる形をとっていました。
現在では、いくつかの機能を種別ごとにまとめたプログラムに他の職種のメンバーと一緒にアサインされるようになり、それぞれが担当のドメインを持つようになりました。Androidチームの各メンバーは、右側の図にある各プログラムのいずれかに所属しています。
これらの変化に対処して、メルペイAndroidチームとしても変化が起こっています。
支払いタブのリニューアルに伴って、UI部分の技術スタックは、Android ViewからJetpack Composeと変わり、リニューアルのタイミングで画面構成や機能にも大幅に変更がありました。
それに伴い、E2Eテストも修正する必要がありました。特に支払いタブは、メルペイが持っているほぼ全ての機能の入口となる画面でもあるので、この部分を修正しないと、E2Eテストの大部分が失敗するという状況でした。
そのため、復旧が急務となり、AndroidチームとしてはチームOKRの一部に組み込む形で、課題に取り組むことにしました。
また、プロジェクトマトリックス体制からプログラム体制へ移行したことに伴い、E2Eテストの実装に関わるメンバー構成も変更しました。具体的には、図の枠で囲った4つのプログラムから、1名ずつE2Eテストの実装に関わるようにしています。各ドメインの機能に精通したメンバーが参加することで、実装時に困った点を解決するまでのスピードが以前と比べて上がりました。
また、実装の優先度を決める際などに、「この画面には近いうちにこういう変更が入る」といった情報をキャッチしやすくなるといった、副次的なメリットもありました。
@shinmiy:こうした変化に対応してチームとして運営していく中で、いろいろな工夫をしています。
弊社で使っているSlackにはハドルという通信機能がありまして、他の会議ツールよりも気軽に集まって話せるようになっているのが特徴です。
この機能を使って1週間の中で定期的に集まる時間を作って、作業通話をしています。私たちの場合は毎週火曜日の午後に、全員が集まれる時間を「わいわい会」と称して作り、その時間に全員でハドルに入ってそれぞれの作業を進めます。
各々が困ったことがあったら、画面共有をしながら全員で問題解決を試みています。特にComposeについてはまだまだ新しい技術なので、手分けをして調べたりアイディアを出し合いながら、うまくテストケースを満たせる実装を探っていっています。
また、メルペイ自体が複雑な機能を持っているということもあり、知らない機能のテスト自動化を担当することもあります。ただ、全員が別々の機能群を担当しているので、お互いに質問し合って、テストケースへの理解を深め合っています。
お互いの忙しさがそれとなく確認できる場でもあるので、作業の進捗を確認して担当するタスクを調整したり、応援したりしています。
タスクの調整には、簡易的なカンバン方式を使っています。社内ツールとしてはJiraを使っているので、テストの追加や修正が必要な場合には、必ず1件ずつJiraでチケットを用意して週の進捗をカンバン方式で管理しています。
あくまでもサブプロジェクトの立ち位置ではあるので、他の大規模なプロジェクトのように、朝会や本格的な進捗確認会は行っていませんが、常に進捗自体は確認できるようにはしています。
最初に、目標として全体で取り組むチケット数やざっくりとしたアサインはメンバー内で決めて、進めていく中でメインの業務のタスクに応じて、定期的に担当を調整しています。
現在の状況を可視化して、メンバー間でお互いに補えるようにすることで、サブプロジェクトながらしっかり目標を達成できるような運用を可能にしています。
E2Eテストの作業では、似たような細かいタスクを大量にこなしていく形になります。普段はメインのタスクの合間に各々がテストを実装するのですが、並行して別々の実装を進めているので、似たような問題に遭遇しやすい状況です。
誰かが問題を解決した一方で、解決策を知らない他のメンバーが類似の問題に直面し、苦労してしまうという悲しいことが起こっています。
解決策をきちんとドキュメント化することも可能ですが、それだけで途方もない時間がかかってしまうので、それぞれが気軽に書き込める「雑にUIテストの知見を記録するメモ」を用意しました。
雑に課題と結論だけを書くドキュメントで、タイポしやすい間違いや、特定のユーザーの状況の作り方まで、実装中に気づいたことやコツ、間違いやすいポイントなどの知見が集まっています。
この知見がテストの実装に役立つことが多く、見返すことで、テストやメルペイ自体の仕様への理解も深まります。苦労して実装した結果を吐き出す場としても機能しており、読んでいくとストレスの発散の跡が見られます。
プルリクエストにもちょっとした工夫をしています。
メルカリ・メルペイの機能はかなり複雑な上に、テストの手順もどうしても言葉だけだと伝わりづらいものが多いので、テストの実装をしている間にテストが動作する様子をキャプチャし、プルリクエストに動画として載せています。
こうすることで、作業者が実現しようとしていることをレビュアーが理解しやすくなる、少なくとも作業者のローカル環境では、テストが通っていることの証拠にもなります。
ローカルでは動いているのにCI上で失敗している場合でも、この動画自体は比較対象として機能するので、どのステップで失敗したかが明確になって、修正にも役立ちます。
最後に、達成会です。有志で集まっている以上は、明確にゴールがあるとモチベーションが保ちやすく、みんなで一つの目標に向かっていくという一体感が出やすくなります。
もちろんチームとしても、「テストの自動化をいくつ完了させる」などの目標は立てていますが、それと合わせて、チームの間で「ここまで完了すれば、達成会を開催しよう」というサブ目標を立てることにしました。
こうすることで、メインの担当のタスクが重なってつらいときでも、「あと何個テストを書けば打ち上げだ」という形でモチベーションが保てるようになりました。
個人的には、TDD(Test-Driven Development)と呼んでいるのですが、あまり浸透はしていないですね。今回は、写真の通りとにかく肉を食べました。
テストの自動化には楽しく取り組めた一方で、大変なことや、課題に感じている改善ポイントもあります。
一つは、とにかく実装に時間がかかること。メルカリアプリの規模に起因する点でもありますが、フルビルドに大体15〜20分ぐらいかかるので、他の作業やミーティングの合間にブランチを切り替えて少しテストを書くという気軽さでは対応できません。
各々作業する時間を確保してテストを書くのですが、どうしても始めるときに「さあやるか」という意気込みとともにビルドボタンを押して、10分ほど待ち、休憩してから作業に戻ります。
また、E2Eの特性上仕方がないことではありますが、結果が不安定なことが多いのも大変な点です。想像以上に時間がかかってテストがタイムアウトしたり、画面遷移の際にうまくタップ対象を認識できなかったりと、安定して成功しないことが多いです。できる限り対策を行うんですけれども、現実的に解決できない問題も多く、ある程度の諦めが肝心です。
特に今の状況では一つのテストがとにかく安定することよりも、自動化されているテストの数を増やすことで、手動テストの負荷を軽減することを目指しています。
それから、仕様変更の部分です。仕様変更によって、せっかく自動化したテストが壊れることもあります。今の仕組み上、仕様変更で実装を変えたときは機能QAを通してリリースするんですが、テストの自動化した部分を直すのはリリースした後で、テストが壊れたのを確認して起票して直すというプロセスを行っています。ここは今後見直していきたいです。
それぞれのメンバーにメインの担当業務があるため、時間の捻出が難しいという課題もあります。プロジェクトの進行上仕方がないので、どのような進め方であれば効率がよいか、いろいろと試すしかないと考えています。
例えば集まる時間を1日にして集中的に実装する、物理的に顔を合わせながら実装して、コミュニケーションコストを下げる日を作るなどいろいろなアイディアはあるのですが、これからいろいろと試していくつもりです。
メルペイでは、リリースサイクルの変更をきっかけにE2Eテストの自動化にずっと取り組んできました。GroundUp Appとともに支払いタブのリニューアルを経て、テストが大幅に壊れた時期もありましたが、Composeのテストの取り組みを始めてテストの追加を頑張ってきた結果、一時期11%程度だったカバレッジが今では約50%と以前と同水準にまで回復させることができました。
ですが、これで終わりではありません。今後も引き続きテストのメンテナンスは必要だと思います。
組織的にも変更がありましたが、有志で集まって工夫をしながら進めた結果、ある程度の土台作りはできました。これからは、コードの変更に対応したテストの運用をしていけるように取り組みたいと思います。
ありがとうございました。