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
半自動E2Eで手っ取り早くリグレッションテストを効率化しよう
Search
Ryuta Kibe
September 19, 2025
Programming
1
200
半自動E2Eで手っ取り早くリグレッションテストを効率化しよう
iOSDC Japan 2025で発表した資料です。
Ryuta Kibe
September 19, 2025
Tweet
Share
Other Decks in Programming
See All in Programming
プロポーザル駆動学習 / Proposal-Driven Learning
mackey0225
2
1.3k
個人軟體時代
ethanhuang13
0
330
テストコードはもう書かない:JetBrains AI Assistantに委ねる非同期処理のテスト自動設計・生成
makun
0
600
個人開発で徳島大学生60%以上の心を掴んだアプリ、そして手放した話
akidon0000
1
170
AI時代のUIはどこへ行く?
yusukebe
18
9.2k
JSONataを使ってみよう Step Functionsが楽しくなる実践テクニック #devio2025
dafujii
1
650
Platformに“ちょうどいい”責務ってどこ? 関心の熱さにあわせて考える、責務分担のプラクティス
estie
1
250
旅行プランAIエージェント開発の裏側
ippo012
2
930
Cache Me If You Can
ryunen344
2
6.1k
AI Agents: How Do They Work and How to Build Them @ Shift 2025
slobodan
0
110
Deep Dive into Kotlin Flow
jmatsu
1
380
Performance for Conversion! 分散トレーシングでボトルネックを 特定せよ
inetand
0
5.6k
Featured
See All Featured
A designer walks into a library…
pauljervisheath
207
24k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
31
2.2k
BBQ
matthewcrist
89
9.8k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.1k
Docker and Python
trallard
46
3.6k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
3k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
285
14k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3k
Being A Developer After 40
akosma
90
590k
Transcript
2025/09/19 Ryuta Kibe 半自動E2Eで手っ取り早く リグレッションテストを効率化しよう @beryu
2
3
目次 1. 効率化する前 2. 自動E2Eテストの構築に挑戦 3. いろいろあって再設計 4. 半自動E2Eテストの実装 5.
付録(時間があれば話す)
1 弊社が効率化する前の リグレッションテスト
リリース前のテスト(頻度:週1) 新しいバージョンを申請する前に iOSエンジニアが手動でリグレッションテストを実施 リグレッションテストを してから 申請
スクラム活動中のテスト(頻度:週1) スクラムのスプリント中にも同様のテストを手動で実施 プランニ ング 開発 レビュー レトロ 開発とスプリントレビューの間で リグレッションテストを実施
毎週2回、手動でリグレッションテストをしていた
去年末まで使用していたテスト項目書の記述 “新規ユーザー登録からの本人確認が完了できる” →どの本人確認書類で手続きすることを指してるの? “マッチングができる” →どんな経路でマッチングすることを指してるの?
作業者によってテストシナリオがブレる どの経路がテストされるかは運任せ
リグレッションテストを 機械化・自動化すれば解決するはず!
2 自動E2Eテストの構築に 着手
自動E2Eテストのアーキテクチャ GitHub CI / CD環境 アプリバイナリ テスト自動化 SaaS E2Eテストを定期 実行
手動操作が不要 クラウド上でE2Eテストを実行
私達には難しかった…
UI要素の検出に失敗(成功することもある) - タップ、スワイプ、といった操作の対象のUI部品が検出できない - 部品が現れるまで待機するコマンドを実行していても失敗する
シミュレータのパフォーマンス問題 - クラウド環境のiPhoneシミュレータの動作が稀に遅くなる - ローカル環境で同じシナリオを実行すると成功する箇所が、クラウド 環境で実行するとタイムアウト
- クラウドにアプリバイナリをアップロードする工程で失敗する - UI要素の検出に成功したり失敗したりする - クラウドで動作するSimulatorのパフォーマンスが悪く、タイムアウトして しまう - 位置情報やプッシュ通知のパーミッションの許可を求めるダイアログが表 示されたりされなかったりする(それが原因でシナリオが失敗する)
- シナリオ実行失敗時、その失敗の直接的な原因を自力では読み取れず、頻 繁にSaaSサポートに問い合わせ - 画面遷移をスワイプ操作で行うような特殊なUIの画面で、遷移が成功した り失敗したりする - SaaSの仕様上の理由でシナリオの部分的なデバッグが難しいケースがあ り、try & errorで時間を浪費してしまう etc… つまずき一覧 他にも細かいつまずきを たくさんしました…
- 私達の知識が足りていないことが主要因 - 挙動を想像出来ていない箇所に問題が集中していた - テスト自動化SaaSは多数の導入実績があり、私達に課題があると考 えるのが自然 - 弊社のAndroidアプリでも、SaaSを用いた自動E2Eテストが既に実現されている 補足:SaaSは悪くない
…トラブルの解消に時間がかかっていた箇所 GitHub CI / CD環境 アプリバイナリ テスト自動化 SaaS E2Eテストを定期 実行
サービス仕様との相性問題も - 一部のシナリオが全自動では実現できない - SMS認証によるサインアップ - SMSが届く電話番号が必要 - QRコードによる出退勤 -
カメラ(シミュレータでは動作しない)が必要
- 2023年10月:調査に着手 - 2024年11月:まだ調査中… 気付けば、着手から1年以上が経過していた
自動E2Eテストの構築・検証に14か月かけた
自動E2Eテストの構築・検証に14か月かけた →それだけチームが実現を望んでいるということ
Done is better than perfect
まずは60〜70点くらいの成果を早く出したい
3 リグレッションテストの 自動化再設計
新アーキテクチャはローカル環境を中心に据えた設計へ ローカルPC app binary $ xcodebuild -scheme … シナリオ テスト自動化
ツール xcodebuild インストール、 UI操作 UI取得 UI取得 インストール、 UI操作
自分たちが最速で成果を出すための技術選定 - Appium - テスト自動化ツール - 歴史と実績が豊富(私も過去に使ったことがある) - XCUITestも考慮したが、有識者が身近にいなかった -
シナリオ記述言語にはRubyを採用 - 弊社のバックエンドがRuby on Rails製 - 稀に私もバックエンドAPIを実装していた - ライブラリが多くリリースされていて、目的が早く達成できそう The Ruby logo is used under the Creative Commons Attribution-ShareAlike 2.5 License. © 2006-2025 Ruby Association, Ruby Developers
方針変更からどれくらいの期間で 運用を開始できたか?
1か月 \ ドヤァ /
4 実装と運用状況
ツールのインストール 後述します
シナリオ開発 基本的には以下の1〜2を繰り返すだけ 1. Appium Inspector(※)の Recording機能で操作を記録 2. 生成されたRubyコードを rubyファイル(.rb)にコピペ (※)https://github.com/appium/appium-inspector
その作業で出来上がるRubyコード el1 = driver.find_element :xpath, "(//XCUIElementTypeNavigationBar[@name=\"AuthScene.LoginView\"]) [2]/XCUIElementTypeButton" # UI部品を検索 el1.click
# 見つかったUI部品をクリック
その作業で出来上がるRubyコード el1 = driver.find_element :xpath, "(//XCUIElementTypeNavigationBar[@name=\"AuthScene.LoginView\"]) [2]/XCUIElementTypeButton" # UI部品を検索 el1.click
# 見つかったUI部品をクリック ちょっと読みにくい…
アプリ実装を改善すれば、こう出来る el1 = driver.find_element :accessibility_id, "login" # UI部品を検索 el1.click #
見つかったUI部品をクリック
アプリ実装を改善すれば、こう出来る el1 = driver.find_element :accessibility_id, "login" # UI部品を検索 el1.click #
見つかったUI部品をクリック ※画像はイメージです
アプリ実装を改善すれば、こう出来る el1 = driver.find_element :accessibility_id, "login" # UI部品を検索 el1.click #
見つかったUI部品をクリック スッキリした!
この改善を全体に適用しま…
この改善を全体に適用しません!
Done is better than perfect
サービス仕様と目的達成の バランスを取りながら工夫を繰り返した
ハードル:(前述)サービス仕様との相性問題 - SMS認証によるサインアップ - SMSが届く電話番号が必要 - QRコードによる出退勤 - カメラ(シミュレータでは動作しない)が必要
工夫: 実機を使うことで出来ない操作をなくす - 手動でSMS認証 - SIMカードを挿した実機を用意 - 手動でQRコードによる出退勤 - 実機のカメラで読み取る
- 手動で操作をする間、シナリオには と書いて待機させておく - 実機でしか利用できない機能を これからもシナリオに追加できる - (例)NFCを用いた出退勤 sleep 30
ハードル: UI部品が検出できない事がある - Appium Inspectorを使ってもOS標準ダイア ログの選択肢のUI部品を検出できなかった - 稀にアクセスできることもある - (SaaSでも同じ問題が起きていた)
UI部品を検出する試行錯誤をしま…
UI部品を検出する試行錯誤をしません!
- OCRを使って画面内から検出した文字列の座標を タップする仕組みをVibe Codingで作った 工夫: UI部品を探さず、特定の文字列を探す OCR.click_default_modal( driver, "アプリにトラッキングしないように要求" )
※上記コードにあるOCRモジュールは自作
- スクリーンショットを加工して精度を上げている - モーダルダイアログの周囲の文字が邪魔 - スクリーンショットを2/3の幅にcrop - 文字色が青いと文字だと認識されにくい - グレースケールに変換
- Rubyライブラリのおかげで短時間で実装できた - rmagick/rmagick(画像加工) - dannnylo/rtesseract(OCR) 工夫: UI部品を探さず、特定の文字列を探す
ハードル: なぜかOCRが失敗するケースがある
- 背景画像がうっすら透けているのが原因 - 私の環境では、たまたま背景との相性が良かったから成功していた ハードル: なぜかOCRが失敗するケースがある 曇りガラス効果により、 ノイズになり得る形が 文字に重なっている
- 手っ取り早く問題を解決したい - rmagickにenhance()というノイズ除去用のメソッドがある - 問題の画像にenhance()を実行すれば問題が解決するのでは…? 工夫: 画像編集ライブラリのノイズ除去メソッドを使う https://rmagick.github.io/image2.html#enhance
enhance()を実行しても解決しなかった… 工夫: 画像編集ライブラリのノイズ除去メソッドを使う image = image.enhance() # (省略: image内の文字を読み取る処理がここに入る) if
scanned_text.end_with?(target_text) # (省略: 検出したテキストの座標をtapする) end
別アプローチの探索をしま…
別アプローチの探索をしません!
成功するまでenhance()を実行し続ける → 成功! 工夫: 画像編集ライブラリのノイズ除去メソッドを使う 30.times do # 検出できるまで最大30回試す image
= image.enhance() # (省略: image内の文字を読み取る処理がここに入る) if scanned_text.end_with?(target_text) # (省略: 検出したテキストの座標をtapする) end end
補足: iOS26対応 Liquid Glassは力技で乗り越えられなかったので、ディザ処理も加えました
ハードル: シャッターボタンが検出できない - Appium Inspectorで 検出できないUI部品 part.2 - 文字ではないのでOCRも使えない
ハードル: シャッターボタンが検出できない iOSのカメラUIの シャッターボタンって だいたいこの辺にあるよね
解決策の汎用化を求め過ぎません!
工夫: 座標指定でタップさせる ”画面のだいたいこの辺”という割合指定で 座標を決め打ちしてタップさせた size = driver.window_size position = [size.width
* 0.5, size.height * 0.95] driver .action .move_to_location(position[0], position[1]) .pointer_down(:left) .release .perform
補足: iOS26対応 シャッターボタンの位置が変わったのでOSバージョン分岐を入れました
ハードル: エンジニアの生産性が上がっていない - 半自動E2Eテストは手動で操作しないといけないタイミングがある - つい端末をずっと見つめてしまって、並列で他の仕事にあたれない! もうすぐ 操作しなきゃ…
手動操作が必要なタイミングで Macに呼んでもらおう いま操作 して!
$ say hello world sayコマンド - 文字列を音声に変換して喋らせるためのコマンド - macOSに標準搭載されている hello
world
# シナリオ側の実装 Say.text("操作が必要です。本人確認を完了させてください。60秒待ちます。") # 呼び出されるメソッド側の実装 def text(message) Thread.new do system(`say
-v Kyoko "#{message}"`) # macOSのsayコマンドに喋らせる end end 工夫5: リグレッションテスト担当者のマルチタスク対応
None
ラクになった!
- E2Eシナリオ拡充 - スクリーンショット撮影機能の追加 - iOS26対応 継続的に改善してます!
5 付録
- “決め”次第で気軽に運用開始できます - 皆様の背中を押すべく、私達が利用しているツール群と Appiumに与えているCapabilities(※)を紹介します (※)Appiumがシナリオ実行を開始する際に用いられるパラメータセットのこと まだ手動で運用している方、チャンスです!
1. Appium (npm install -g appium) 2. carthage (brew install
carthage) 3. Appium XCUITest Driver (appium driver install xcuitest) 4. (画像加工をする場合) imagemagick (brew install imagemagick@6) 5. (OCRを実施する場合) tesseract (brew install tesseract) - 日本語対応のため、 https://github.com/tesseract-ocr/tessdata の jpn.traineddataも必要 ※赤字のみ必須、他は任意 私達が利用しているツール
設定類 - AppiumのCapabilities設定JSON - Appiumに渡す.appファイルを作るアーカイブコマンド { "appium:platformName": "iOS", "appium:automationName": "XCUITest",
"appium:udid": "{デバイスID}", "appium:autoFillPasswords": false, "appium:language": "ja-JP", "appium:newCommandTimeout": 480000, "appium:app": "{.appファイルのパス}" } $ xcodebuild -scheme {スキーム名} \ -configuration Debug \ -sdk iphoneos \ -archivePath /path/to/app.xcarchive archive { "appium:platformName": "iOS", "appium:automationName": "XCUITest", "appium:udid": "{デバイスID}", "appium:autoFillPasswords": false, "appium:language": "ja-JP", "appium:newCommandTimeout": 480000, "appium:bundleId": "{インストール済のアプリの BundleID}" } アプリを新規インストールする場合 インストール済のアプリを利用する場合
岐部 龍太(きべ りゅうた) 株式会社タイミー iOSテックリード GitHub / X: @beryu 居住地:
福岡🍜