Upgrade to Pro — share decks privately, control downloads, hide ads and more …

手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごと...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for otouto otouto
September 13, 2026

手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest

iOSDC Japan 2026にて登壇した内容になります。
https://fortee.jp/iosdc-japan-2026/proposal/7d125d0b-f834-49c5-8431-11cf313be2ff
----------------------------------------------------------------

ー「Custom URL Schemeから起動すると正しい画面に遷移しない」ー
そんな不具合に遭遇したことはないでしょうか。

Custom URL Scheme(以下、URLスキーム)は、アプリの特定の画面へ遷移させるために利用されます。
弊社のアプリでも多くのURLスキームがあり、処理の追加や修正があると遷移を手動確認していました。
しかし、URLスキームの確認対象が増えるにつれて工数が膨らみ、確認漏れによる不具合も発生していました。
そこで、この課題を解決するためにXCUITestを利用し、URLスキームの遷移確認を自動化しました。

ただし、URLスキームのテストは単にURLを開くだけでは十分ではありません。
WWDCのセッションでも整理されているように、アプリにはCold Start・Warm Start・Resumeという異なる起動種別があり、呼び出される処理が異なります。
そのため、URLスキームの動作を網羅的にテストするには、起動種別を考慮したテスト設計が重要になります。
さらに、Resumeのテストは単純な方法では期待どおりに再現できず、試行錯誤が必要でした。

このトークで話すこと

本トークでは、混同しがちなアプリの起動種別を整理し、その違いを踏まえたURLスキームのテスト方法を紹介します。

・URLスキームのテストに手間がかかる理由
・アプリの起動種別(Cold Start / Warm Start / Resume)の違い
・起動種別を考慮したテスト設計
・XCUITestでURLスキームの動作を検証する方法
・Resumeを確認するために行った実装

URLスキームは一度実装すると長く利用される一方で、デグレが起きても気付きにくい機能です。
本トークを通じて、URLスキームのデグレを検知するテストの実装方法を知ることができます!

Avatar for otouto

otouto

September 13, 2026

More Decks by otouto

Other Decks in Programming

Transcript

  1. 起動種別について整理する 起動種別 プロセス メモリ 例 Cold Start なし なし 端末再起動後

    Warm Start なし ⼀部キャッシュ 終了直後の起動 Resume あり 全保持 サスペンドから復帰 参考︓WWDC19 "Optimizing App Launch" 9
  2. 起動種別について整理する 起動種別 プロセス メモリ 例 Cold Start なし なし 端末再起動後

    Warm Start なし ⼀部キャッシュ 終了直後の起動 scene(_:willConnectTo:options:) Resume あり 全保持 サスペンドから復帰 scene(_:openURLContexts:) 10
  3. 起動種別について整理する 起動種別 プロセス メモリ 例 Cold Start なし なし 端末再起動後

    Warm Start なし ⼀部キャッシュ 終了直後の起動 Launch Resume Resume scene(_:willConnectTo:options:) あり 全保持 サスペンドから復帰 scene(_:openURLContexts:) 11
  4. Resumeのテストでつまづいたところ XCUIApplication func open(_ url: URL) Launches the application by

    URL. open(_:)は呼ぶたびに、アプリを終了 して起動し直す 26
  5. テストに必要なプロトコルのコード import XCTest /// Launchのテスト func assertLaunch() { app.open(schemeURL) ///

    URLスキームテストに必要な要素を定義するプロトコル protocol URLSchemeTestable: XCTestCase { /// スキームのホスト名(例: "iosdc") var schemeHost: String { get } /// クエリパラメータ var queryItems: [URLQueryItem] { get } /// 遷移先の画⾯要素 var targetElement: XCUIElement { get } /// クエリパラメータの反映を検証する要素 var queryAssertionElement: XCUIElement? { get } } XCTAssertTrue(targetElement.waitForExistence(timeout: 10)) if let element = queryAssertionElement { XCTAssertTrue(element.exists) // クエリの反映も⾒たいスキームだけ } } /// Resumeのテスト func assertResume() { app.launch() XCUIDevice.shared.system.open(schemeURL) extension URLSchemeTestable { var app: XCUIApplication { XCUIApplication() } var queryAssertionElement: XCUIElement? { nil } var schemeURL: URL { var components = URLComponents() components.scheme = "myapp" components.host = schemeHost components.queryItems = queryItems return components.url! } // 起動させ、Launchを検証する // 「起動済み」の状態を作る // システムにURLを開かせる XCTAssertTrue(targetElement.waitForExistence(timeout: 10)) if let element = queryAssertionElement { XCTAssertTrue(element.exists) } } } 34
  6. プロトコルを確認したい画⾯に準拠 import XCTest final class IOSDCSchemeTests: XCTestCase { func test_Launch_iosdcスキームで詳細画⾯が表⽰される()

    { assertLaunch() } func test_Resume_iosdcスキームで詳細画⾯に遷移する() { assertResume() } } extension IOSDCSchemeTests: URLSchemeTestable { var schemeHost: String { "iosdc" } var queryItems: [URLQueryItem] { [URLQueryItem(name: "year", value: "2026")] } var targetElement: XCUIElement { app.otherElements["IOSDCDetailViewController"] } var queryAssertionElement: XCUIElement? { app.staticTexts["iOSDC 2026"] } } 35