Slide 1

Slide 1 text

モバイル交通系ICへのチャージ実例から考える、 クロスプラットフォーム開発における iOS実機テスト設計とCI運用 東日本旅客鉄道株式会社 アクセンチュア株式会社 菅原 祐 1 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 2

Slide 2 text

アクセンチュア株式会社 菅原 祐 yusuga 2 𝕏 @yusuga_ Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 3

Slide 3 text

東日本旅客鉄道株式会社 「Suicaアプリ(仮称)」開発プロジェクト iOS・Androidアプリの設計・実装 KMPで両OSの共通ロジックを設計・実装 CIの構築・運用 3 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 4

Slide 4 text

昨日のルーキーズ LT 4 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 5

Slide 5 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 5 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 6

Slide 6 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 6 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 7

Slide 7 text

1 ICカードからセンターサーバーへ 1. 出典: Suicaの当たり前を超えます 〜Suica Renaissance〜 ↩︎ 7 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 8

Slide 8 text

1 2028年度のリリースに向け開発中 1. 出典: Suicaの当たり前を超えます 〜Suica Renaissance〜 ↩︎ 8 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 9

Slide 9 text

カード型のSuica JR東日本の交通系ICカード – 改札にタッチして乗車 – 電子マネーで支払い – 券売機でチャージ – 残高はカード内に記録 9 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 10

Slide 10 text

モバイルSuica 9:41 SuicaをiPhoneの中で管理 – iPhoneをタッチして乗車・ 支払い – 残高はiPhone内のICチップ に記録 – 発行・チャージ・グリーン 券・定期券購入がアプリで 完結 出典: App Store「Suica」1 1. iPhoneは、米国および他の国々で登録されたApple Inc.の商標です。App StoreはApple Inc.のサービスマークです。 ↩︎ 10 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 11

Slide 11 text

Suicaアプリ(仮称) カード型のSuica 2001年〜 提供中 モバイルSuica 2006年〜(iPhoneは2016年〜) Suicaアプリ(仮称) 2028年度 提供予定 9:41 開発中 11 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 12

Slide 12 text

Suicaアプリ(仮称)の主機能 アプリからSuicaの読み書き – Suicaの新規発行 – チャージ – グリーン券・定期券購入 12 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 13

Slide 13 text

Suicaの読み書きの確認方法 – シミュレータにはICチップがない – 動作確認には実機が必須 13 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 14

Slide 14 text

実機で継続的に動作確認する方法 人による動作確認 vs 実機自動テスト 14 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 15

Slide 15 text

実機で継続的に動作確認する方法 人による動作確認 vs 実機自動テスト 15 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 16

Slide 16 text

実機でしか確認できない機能例 今日の題材 IC NFCタグを 読み取る 対象: 外部のタグ Bluetooth機器と 通信する 対象: 外部の機器 カメラで QRコードを読む 対象: 現実の被写体 ICチップへ アクセスする 対象: 端末内のICチップ ほかにも 位置情報、外部デバイス連携 など 16 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 17

Slide 17 text

チャージ時に何が起きているか 17 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 18

Slide 18 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 18 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 19

Slide 19 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス ❶ チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 19 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 20

Slide 20 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ❷ ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 20 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 21

Slide 21 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 21 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 22

Slide 22 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 22 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 23

Slide 23 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 23 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 24

Slide 24 text

チャージ時に何が起きているか チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 UI操作 UI操作 APIサーバーへのアクセス ❻ ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 24 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 25

Slide 25 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 25 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 26

Slide 26 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 26 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 27

Slide 27 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 27 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 28

Slide 28 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 28 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 29

Slide 29 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 29 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 30

Slide 30 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 30 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 31

Slide 31 text

それぞれの動作確認観点 チャージ処理 テスト設計の論点 ❶ 金額・決済方法を選択 UIと状態更新の確認方法 ❷ チャージ確定ボタンを押下 処理の呼び出し確認方法 ③ API通信 通信を差し替えるのか、実環境か ④ 3DS認証(必要な場合) 認証結果のみ確認か、フロー全体か ⑤ ICチップ書き込み 処理を差し替えるか、実機書き込みか ❻ チャージ成功 UIと状態更新の確認方法 UI操作 UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 31 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 32

Slide 32 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 32 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 33

Slide 33 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 33 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 34

Slide 34 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 34 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 35

Slide 35 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 35 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 36

Slide 36 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 36 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 37

Slide 37 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 37 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 38

Slide 38 text

共通処理とOS固有の処理がある チャージ処理 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 ※アプリ画面は説明用のイメージで、実際の開発画面とは異なります 38 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 39

Slide 39 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 39 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 40

Slide 40 text

共通処理とOS固有処理の分け方 チャージ処理 40 ❶ 金額・決済方法を選択 ❷ チャージ確定ボタンを押下 ③ API通信 ④ 3DS認証(必要な場合) ⑤ ICチップ書き込み ❻ チャージ成功 共通 画面と選択状態 UI操作 チャージ処理を呼ぶ UI操作 APIサーバーへのアクセス ブラウザを利用した認証 ICチップへのアクセス チャージ結果と残高を画面に反映 OS固有 通信とデータ操作 呼び出しと分岐 認証画面の表示 呼び出しと判定 ICチップ書き込み 成功・失敗の判定 残高と結果の表示 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 41

Slide 41 text

なぜレイヤーを分けたいのか – 人の手を使わずに動作確認をしたい – 自動でテスト可能な構成にしなければいけな い – それぞれの処理を差し替えられるようにしな ければいけない 41 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 42

Slide 42 text

1 採用したアーキテクチャ 責務の分け方 それぞれの責務 UI Layer UI elements State holders Domain Layer UI Layer 表示する内容を組み立てて画面に描く 画面の状態を保持し、処理を呼び出す Domain Layer 画面にもデータの取得元にも依存しない アプリ固有の処理の流れを組み立てる Data Layer Repositories Data Sources Data Layer データの取得元を隠し、アプリの形へ変換する OS・端末・ネットワークに実際に触れる 1. Android アプリ アーキテクチャ ガイドを元に作成 ↩︎ 42 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 43

Slide 43 text

1 採用したアーキテクチャ 責務の分け方 それぞれの責務 UI Layer UI elements State holders Domain Layer UI Layer 表示する内容を組み立てて画面に描く 画面の状態を保持し、処理を呼び出す Domain Layer 画面にもデータの取得元にも依存しない アプリ固有の処理の流れを組み立てる Data Layer Repositories Data Sources Data Layer データの取得元を隠し、アプリの形へ変換する OS・端末・ネットワークに実際に触れる 1. Android アプリ アーキテクチャ ガイドを元に作成 ↩︎ 43 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 44

Slide 44 text

1 採用したアーキテクチャ 責務の分け方 それぞれの責務 UI Layer UI elements State holders Domain Layer UI Layer 表示する内容を組み立てて画面に描く 画面の状態を保持し、処理を呼び出す Domain Layer 画面にもデータの取得元にも依存しない アプリ固有の処理の流れを組み立てる Data Layer Repositories Data Sources Data Layer データの取得元を隠し、アプリの形へ変換する OS・端末・ネットワークに実際に触れる 1. Android アプリ アーキテクチャ ガイドを元に作成 ↩︎ 44 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 45

Slide 45 text

1 採用したアーキテクチャ 責務の分け方 それぞれの責務 UI Layer UI elements State holders Domain Layer UI Layer 表示する内容を組み立てて画面に描く 画面の状態を保持し、処理を呼び出す Domain Layer 画面にもデータの取得元にも依存しない アプリ固有の処理の流れを組み立てる Data Layer Repositories Data Sources Data Layer データの取得元を隠し、アプリの形へ変換する OS・端末・ネットワークに実際に触れる 1. Android アプリ アーキテクチャ ガイドを元に作成 ↩︎ 45 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 46

Slide 46 text

チャージ画面のレイヤー構成 View UI Layer iOS / Android 金額・決済方法の選択、チャージ操作、結果の表示 画面を描画 StateHolder 選択状態を保持し、ChargeUseCaseを呼び出す Domain Layer iOS / Android UseCase チャージ完了までの処理フローを制御する Repository Data Layer iOS / Android チャージや残高に関するデータ操作を提供する DataSource API通信などの具体的な入出力を行う ※資料用に編集しており、実際の構成を正確に表しているものではありません 46 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 47

Slide 47 text

UIはネイティブの表現を使用したい View UI Layer iOS / Android 金額・決済方法の選択、チャージ操作、結果の表示 StateHolder 画面を描画 各OSの ネイティブ で表現 選択状態を保持し、ChargeUseCaseを呼び出す Domain Layer iOS / Android UseCase チャージ完了までの処理フローを制御する Repository Data Layer iOS / Android チャージや残高に関するデータ操作を提供する DataSource API通信などの具体的な入出力を行う ※資料用に編集しており、実際の構成を正確に表しているものではありません 47 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 48

Slide 48 text

複雑な仕様を両OSで揃えたい View 金額・決済方法の選択、チャージ操作、結果の表示 UI Layer 画面を描画 StateHolder 選択状態を保持し、ChargeUseCaseを呼び出す Domain Layer UseCase チャージ完了までの処理フローを制御する Repository チャージや残高に関するデータ操作を提供する Data Layer iOS / Androidで 共通 DataSource API通信などの具体的な入出力を行う ※資料用に編集しており、実際の構成を正確に表しているものではありません 48 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 49

Slide 49 text

処理を共通化 責務の分け方 実装の持ち方 UI Layer UI elements State holders iOS / Android それぞれ実装 Domain Layer Data Layer Repositories KMP(共通) Kotlinで1つ Data Sources 49 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 50

Slide 50 text

KMP(Kotlin Multiplatform)とは – Kotlinで書いた処理をAndroid・iOS向けにそ れぞれコンパイル – 複雑な処理をワンソース化 できるのがメリッ ト 50 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 51

Slide 51 text

SwiftからKMPを使用する iOS Swift import / 呼び出し XCFramework KMP Kotlin UseCase Repository DataSource Objective-C互換API ビルド 自動生成されるヘッダー bridge Kotlin/Nativeバイナリ Kotlinランタイム UseCase、Repository、DataSource 51 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 52

Slide 52 text

SwiftからKMPを使用する iOS Swift import / 呼び出し XCFramework KMP Kotlin UseCase Repository DataSource Objective-C互換API ビルド 自動生成されるヘッダー bridge Kotlin/Nativeバイナリ Kotlinランタイム UseCase、Repository、DataSource 52 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 53

Slide 53 text

SwiftからKMPを使用する iOS Swift import / 呼び出し XCFramework KMP Kotlin UseCase Repository DataSource Objective-C互換API ビルド 自動生成されるヘッダー bridge Kotlin/Nativeバイナリ Kotlinランタイム UseCase、Repository、DataSource 53 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 54

Slide 54 text

処理を共通化 View UI Layer iOS / Android 金額・決済方法の選択、チャージ操作、結果の表示 画面を描画 StateHolder 選択状態を保持し、ChargeUseCaseを呼び出す Domain Layer KMP(共通) UseCase チャージ完了までの処理フローを制御する Repository Data Layer KMP(共通) チャージや残高に関するデータ操作を提供する DataSource API通信などの具体的な入出力を行う ※資料用に編集しており、実際の構成を正確に表しているものではありません 54 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 55

Slide 55 text

KMPは必須条件ではない View UI Layer iOS / Android 金額・決済方法の選択、チャージ操作、結果の表示 画面を描画 StateHolder 選択状態を保持し、ChargeUseCaseを呼び出す Domain Layer iOS / Android UseCase チャージ完了までの処理フローを制御する Repository Data Layer iOS / Android チャージや残高に関するデータ操作を提供する Swiftで 実装して もよい DataSource API通信などの具体的な入出力を行う ※資料用に編集しており、実際の構成を正確に表しているものではありません 55 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 56

Slide 56 text

レイヤーで責務を分ける iOS KMP(共通) Android View / StateHolder View / StateHolder ChargeUseCase Repository DataSource ※資料用に編集しており、実際の構成を正確に表しているものではありません 56 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 57

Slide 57 text

共通処理とOS固有処理をつなぐ iOS KMP(共通) Android View / StateHolder View / StateHolder ChargeUseCase Repository 呼び出し 3DS呼び出しI/F 呼び出し 3DS認証画面 3DS認証画面 認証結果 認証結果 ICチップ書き込みI/F 書き込み 書き込み ICチップ書き込み ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 57 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 58

Slide 58 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 58 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 59

Slide 59 text

1 非効率的な戦略の例 E2E 手動QA リリースビルドで 週1回実行 E2E 実機テスト 通常はCIで 夜間に実行 コンポーネント UIテスト 通常はCIで マージ前に実行 単体テスト 通常はローカルで コミット前に実行 1. 出典: Android Developers「テスト戦略」図2 ↩︎ 59 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 60

Slide 60 text

1 スケーラブルなテスト戦略 リリース 候補版のテスト 統合 アプリケーションテスト スコープ 忠実性 実行時間 機能テスト コンポーネントテスト 分離 単体テスト 1. 出典: Android Developers「テスト戦略」図3 ↩︎ 60 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 61

Slide 61 text

テスト手法 手法 確かめる範囲 単体テスト 単一のメソッドやクラス コンポーネントテスト 独立させたモジュールやコンポーネント 機能テスト 複数のコンポーネント間の連携 アプリケーションテスト デプロイ可能なアプリ全体 リリース候補版のテスト 本番に近い環境で動かすアプリ全体 61 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 62

Slide 62 text

iOSのテスト手段 手段 テストの入口 Swift Testing / XCTest テストコードから処理を直接呼ぶ XCUITest UIを通してアプリを操作する 62 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 63

Slide 63 text

iOSのテスト手段 テスト手段 メリット デメリット Swift Testing / XCTest 高速で安定して実行 できる 画面表示やユーザー操作は確認できない XCUITest ユーザー操作から一 連の動作を確認でき る アプリ起動や画面描画を伴うため遅く、待機タ イミングやUI変更の影響で不安定になりやすい 63 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 64

Slide 64 text

この発表でのテスト用語 用語 確かめる範囲 テスト手段 単体テスト 単一のメソッドやクラス Swift Testing 機能テスト 複数のコンポーネント間の連携 Swift Testing UIテスト 画面表示とユーザー操作 XCUITest 64 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 65

Slide 65 text

この発表でのテスト用語 用語 確かめる範囲 テスト手段 単体テスト 単一のメソッドやクラス Swift Testing 機能テスト 複数のコンポーネント間の連携 Swift Testing UIテスト 画面表示とユーザー操作 XCUITest 65 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 66

Slide 66 text

各レイヤーのテスト責務 66 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 67

Slide 67 text

Viewは、UIテストで確かめる iOS UIテスト KMP(共通) Android UIテスト View View StateHolder StateHolder 処理を差し替え 処理を差し替え ChargeUseCase Repository DataSource 3DS認証・ICチップ書き込み 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 67 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 68

Slide 68 text

StateHolderは、単体テストで確かめる iOS KMP(共通) Android View View 単体テスト 単体テスト StateHolder StateHolder ChargeUseCase 処理を差し替え Repository DataSource 3DS認証・ICチップ書き込み 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 68 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 69

Slide 69 text

UseCaseは、単体テストで確かめる iOS KMP(共通) Android View View StateHolder StateHolder 単体テスト ChargeUseCase Repository 処理を差し替え DataSource 3DS認証・ICチップ書き込み 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 69 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 70

Slide 70 text

Repositoryは、単体テストで確かめる iOS KMP(共通) Android View View StateHolder StateHolder ChargeUseCase 単体テスト Repository DataSource 処理を差し替え 3DS認証・ICチップ書き込み 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 70 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 71

Slide 71 text

DataSourceは、必要なら単体テストする iOS KMP(共通) Android View View StateHolder StateHolder ChargeUseCase Repository 自前ロジックだけ単体テスト DataSource 処理を差し替え 3DS認証・ICチップ書き込み 3DS認証・ICチップの振る舞いを 本物同等に模倣できない 処理を差し替え 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 71 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 72

Slide 72 text

ICチップの書き込みに適したテスト手法は? 手法 メリット デメリット 単体テ スト 高速・安定して繰り返せる 複数の処理がまたがるICチップへの書き 込みは確認しづらい 機能テ スト チャージ画面を操作せず実処 理を確認できる 画面表示・操作は確認できない UIテス ト ユーザー操作から一連の動作 を確認できる 遅く、UI変更の影響を受けやすい 72 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 73

Slide 73 text

ICチップの書き込みに適したテスト手法は? 手法 メリット デメリット 単体テ スト 高速・安定して繰り返せる 複数の処理がまたがるICチップへの書き 込みは確認しづらい 機能テ スト チャージ画面を操作せず実処 理を確認できる 画面表示・操作は確認できない UIテス ト ユーザー操作から一連の動作 を確認できる 遅く、UI変更の影響を受けやすい 73 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 74

Slide 74 text

実機でUseCaseから一連の処理を確認 iOS 実機での機能テスト KMP(共通) Android 実機での機能テスト iPhone実機 Android実機 Swift Testing Instrumented Test ChargeUseCase 処理を差し替え Repository DataSource 3DS認証・ICチップ書き込み 3DS認証・ICチップ書き込み ※資料用に編集しており、実際の構成を正確に表しているものではありません 74 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 75

Slide 75 text

UseCaseから確認する理由 – 上位レイヤーだと確認対象外の影響も受ける – UIテスト: View・StateHolderの影響を受け る – StateHolderのテスト: View向けの状態管理 の影響を受ける – チャージの処理フローだけを確認するため UseCaseを直接実行 75 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 76

Slide 76 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 76 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 77

Slide 77 text

突然ですが、 新幹線は好きですか? 77 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 78

Slide 78 text

1 新幹線 はやぶさ 運行区間 最高速度 E5系 東北新幹線、北海道新幹線 320km/h つばさ 運行区間 最高速度 E8系 山形新幹線、東北新幹線 300km/h 1. 出典: E5系 / E8系 - JR東日本 ↩︎ 78 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 79

Slide 79 text

実機テストを走らせる「はやぶさ」と「つばさ」 はやぶさ CPU メモリ 79 Mac Studio M4 Max 16 cores 128 GB つばさ CPU メモリ MacBook Pro M4 Pro 12 cores 48 GB Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 80

Slide 80 text

JR東日本管内速度ランキング(登壇者調べ1) Tier 速度 車両・対象 愛称・列車名 位置づけ S 360km/h 試験 E956形 ALFA-X 営業車両ではなく試験車両。高速営業化を見据え た試験領域。 A 320km/h 営業 E5系 / E6系 はやぶさ / こまち / はやて / やまびこ / なすの JR東日本の現行営業最速帯。主に東北新幹線高速 区間。 B 300km/h 営業 E8系 つばさ / なすの 山形新幹線向け新型。東北新幹線区間で300km/h 対応。 C 275km/h 営業 E7系 / E2系 / E3系 かがやき / はくたか / あさま / とき / たにがわ / やま びこ / なすの / つばさ JR東日本の標準的な高速帯。 D 240km/h 級以下 各形式 各列車 東京〜大宮周辺など、都市部・騒音・線形制約に よる速度制限区間。 E 130km/h 級 E3系 / E6系 / E8系 つばさ / こまち 山形・秋田新幹線の在来線直通区間。フル規格新 幹線区間ではない。 1. JR東日本の公開情報をもとに登壇者が整理した参考情報で、公式の比較資料ではありません ↩︎ 80 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 81

Slide 81 text

GitHub Actions の Runner GitHub-hosted runner Self-hosted runner マシン GitHubが用意 自分たちが用意 実行環境 Jobごとに新しい環境 登録したマシンを利用 ハードウェア GitHubの構成から選択 用途に合わせて選択 社内ネットワー ク・接続機器 VPN等の接続構成が必要・手元の 機器は直接接続不可 マシンから到達・接続でき る範囲で利用可能 OS・ツールの保 守 GitHub 自分たち 81 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 82

Slide 82 text

Runnerの構成図 GitHub-hosted GitHub Actions Self-hosted hayabusa tsubasa M4 Max 16 cores / Memory 128 GB M4 Pro 12 cores / Memory 48 GB Mac Studio (2025) iPhone ×3 Android ×3 82 A A MacBook Pro (14-inch, 2024) B B C C iPhone ×2 Android ×1 D E D Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 83

Slide 83 text

Runnerの構成図 GitHub-hosted GitHub Actions Self-hosted hayabusa tsubasa M4 Max 16 cores / Memory 128 GB M4 Pro 12 cores / Memory 48 GB Mac Studio (2025) iPhone ×3 Android ×3 83 A A MacBook Pro (14-inch, 2024) B B C C iPhone ×2 Android ×1 D E D Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 84

Slide 84 text

Runnerの構成図 GitHub-hosted GitHub Actions Self-hosted hayabusa tsubasa M4 Max 16 cores / Memory 128 GB M4 Pro 12 cores / Memory 48 GB Mac Studio (2025) iPhone ×3 Android ×3 84 A A MacBook Pro (14-inch, 2024) B B C C iPhone ×2 Android ×1 D E D Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 85

Slide 85 text

Runnerの構成図 GitHub-hosted GitHub Actions Self-hosted hayabusa tsubasa M4 Max 16 cores / Memory 128 GB M4 Pro 12 cores / Memory 48 GB Mac Studio (2025) iPhone ×3 Android ×3 85 A A MacBook Pro (14-inch, 2024) B B C C iPhone ×2 Android ×1 D E D Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 86

Slide 86 text

Suicaの状態もテスト環境として管理 A 実機A Suicaが0枚 初めてのSuicaを作成できる状態 作成 → チャージ → 退会・払戻 を通しで確認できる B 実機B 有効 有効 無効 別の状態 Suicaが4枚。有効・無効など、それぞれ異なる状態 1台で複数の開始条件をまかなう … 86 その他の実機 … … … … テストシナリオに応じた状態を用意する Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 87

Slide 87 text

Suicaの状態もテスト環境として管理 A 実機A Suicaが0枚 初めてのSuicaを作成できる状態 作成 → チャージ → 退会・払戻 を通しで確認できる B 実機B 有効 有効 無効 別の状態 Suicaが4枚。有効・無効など、それぞれ異なる状態 1台で複数の開始条件をまかなう … 87 その他の実機 … … … … テストシナリオに応じた状態を用意する Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 88

Slide 88 text

Suicaの状態もテスト環境として管理 A 実機A Suicaが0枚 初めてのSuicaを作成できる状態 作成 → チャージ → 退会・払戻 を通しで確認できる B 実機B 有効 有効 無効 別の状態 Suicaが4枚。有効・無効など、それぞれ異なる状態 1台で複数の開始条件をまかなう … 88 その他の実機 … … … … テストシナリオに応じた状態を用意する Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 89

Slide 89 text

テストシナリオと実行環境を対応づける 89 テストケース Self-hosted runner 実行する端末 対象のSuica 新規作成したSuicaへチャージできる hayabusa Mac Studio A Suicaが0枚 登録済みのSuicaへチャージできる hayabusa Mac Studio B 有効なSuica 無効なSuicaへはチャージできない hayabusa Mac Studio B 無効なSuica その他 tsubasa MacBook Pro … … Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 90

Slide 90 text

テストシナリオと実行環境を対応づける 90 テストケース Self-hosted runner 実行する端末 対象のSuica 新規作成したSuicaへチャージできる hayabusa Mac Studio A Suicaが0枚 登録済みのSuicaへチャージできる hayabusa Mac Studio B 有効なSuica 無効なSuicaへはチャージできない hayabusa Mac Studio B 無効なSuica その他 tsubasa MacBook Pro … … Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 91

Slide 91 text

テストシナリオと実行環境を対応づける 91 テストケース Self-hosted runner 実行する端末 対象のSuica 新規作成したSuicaへチャージできる hayabusa Mac Studio A Suicaが0枚 登録済みのSuicaへチャージできる hayabusa Mac Studio B 有効なSuica 無効なSuicaへはチャージできない hayabusa Mac Studio B 無効なSuica その他 tsubasa MacBook Pro … … Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 92

Slide 92 text

テストシナリオと実行環境を対応づける 92 テストケース Self-hosted runner 実行する端末 対象のSuica 新規作成したSuicaへチャージできる hayabusa Mac Studio A Suicaが0枚 登録済みのSuicaへチャージできる hayabusa Mac Studio B 有効なSuica 無効なSuicaへはチャージできない hayabusa Mac Studio B 無効なSuica その他 tsubasa MacBook Pro … … Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 93

Slide 93 text

実機テスト環境のファイル構成 93 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 94

Slide 94 text

実機テスト環境のファイル構成 ※ 実機管理に必要な観点を示すための構成例 ファイル .github/workflows/suica-devicetest.yml scenarios.yml 記載すること GitHub Actions の Workflow テスト内容、parameter、実行方法、固定 Target inventory.yml Runner、実機、Suica、Targetの対応関係 secrets.env 実機の識別情報とSuicaのIDの実値 dispatch.sh 実行環境を確認してKotlin製CLIを起動 94 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 95

Slide 95 text

scenarios.yml 1 シナリオ名、parameter、実行方法、固定Targetを定義 scenarios: sf-charge.registered-card.success: parameters: amount: 500 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 95 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 96

Slide 96 text

scenarios.yml シナリオ名、parameter、実行方法、固定Targetを定義1 executions: ios: target: ios-charge-target workingDirectory: ios scheme: SuicaApp onlyTesting: SuicaTests/ChargeDeviceTests/chargeSucceeds executionGate: name: ENABLE_CHARGE_TEST value: "1" parameterEnvironment: amount: CHARGE_AMOUNT 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 96 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 97

Slide 97 text

scenarios.yml Androidの定義1 android: target: android-charge-target workingDirectory: . gradleTask: connectedChargeTest # 独自タスク testClass: ChargeSuccessTest # パッケージ名は省略 executionGate: name: enableChargeTest value: "true" parameterArguments: amount: chargeAmount 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 97 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 98

Slide 98 text

inventory.yml TargetからSuica・実機・Runnerを特定 1 targets: ios-charge-target: kind: suica suica: iphone-a.charge android-charge-target: kind: suica suica: android-a.charge 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 98 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 99

Slide 99 text

inventory.yml TargetからSuica・実機・Runnerを特定 1 suicas: iphone-a.charge: device: iphone-a idRef: iphone-a.charge.suica-id android-a.charge: device: android-a idRef: android-a.charge.suica-id 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 99 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 100

Slide 100 text

inventory.yml TargetからSuica・実機・Runnerを特定1 devices: iphone-a: runner: hayabusa platform: ios udidRef: iphone-a.udid android-a: runner: hayabusa platform: android serialRef: android-a.serial 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 100 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 101

Slide 101 text

inventory.yml TargetからSuica・実機・Runnerを特定1 runners: hayabusa: labels: [self-hosted, macOS, ARM64, hayabusa] 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 101 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 102

Slide 102 text

secrets.env 1 実機とSuicaの識別情報を保存 iphone-a.udid=00008110-DEADBEEFDEADBEEF iphone-a.charge.suica-id=0123456789 android-a.serial=R3CT00DEADBEEF android-a.charge.suica-id=9876543210 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 102 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 103

Slide 103 text

dispatch.sh 1 Kotlin製CLIを起動する薄いwrapper # script_dirはツール直下(解決・存在確認は省略) dist_dir="$script_dir/build/install/suica-device-test" cli="$dist_dir/bin/suica-device-test" # 引数をそのまま渡して起動 exec "$cli" "$@" 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 103 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 104

Slide 104 text

Kotlin製CLI 設定を検証し、実機テストを組み立てて実行 1 // 設定から実行計画を解決 val scenario = ScenarioResolver(...).resolve( scenarioAlias, scenarioDefinition, inventory, ) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 104 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 105

Slide 105 text

Kotlin製CLI 設定を検証し、実機テストを組み立てて実行 1 // 指定された実行定義を取得(未定義ならエラー) val execution = scenario.executions.getValue(command.execution) // 秘密情報を読み込む val secrets = secretSource.load(...) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 105 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 106

Slide 106 text

Kotlin製CLI 設定を検証し、実機テストを組み立てて実行 1 // iOS: TEST_RUNNER_を付けてxcodebuildへ渡す // 対象IDの固定名: iOSはSUICA_ID、AndroidはsuicaId val environment = EnvironmentBuilder.build(execution, secrets) // OSごとのテストコマンドを構築 val testCommand = CommandBuilder.build(execution, secrets) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 106 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 107

Slide 107 text

Kotlin製CLI 設定を検証し、実機テストを組み立てて実行 1 // 環境変数とともに対象実機で実行 processRunner.execute( testCommand, environment, execution.workingDirectory, execution.target, ) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 107 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 108

Slide 108 text

Kotlin製CLI iOSのTest commandを組み立てる1 // OSに応じてテストコマンドを組み立てる when (val definition = execution.definition) { is IosExecutionDefinition -> { val destination = DestinationBuilder.build( execution.target, secrets, ) listOf( "/usr/bin/xcodebuild", "test", "-scheme", definition.scheme, "-destination", destination, "-only-testing:${definition.onlyTesting}", ) } 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 108 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 109

Slide 109 text

Kotlin製CLI AndroidのTest commandを組み立てる1 is AndroidExecutionDefinition -> // gate・金額・秘密情報から解決した対象IDも追加 listOf( "./gradlew", definition.gradleTask, "-Pandroid.testInstrumentationRunnerArguments" + ".class=${definition.testClass}", ) + InstrumentationArgumentsBuilder.build( execution, secrets, ) } 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 109 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 110

Slide 110 text

1 実機テストCLIの処理フロー dispatch.sh Kotlin製CLI iOS / ENVはテスト側の名前 shell / 薄いwrapper 実機テストの制御を集約 ENV 実行場所を解決 引数を解析 CMD Kotlin製CLIの存在確認 設定を読み込み・検証 tool rootを設定 Target・実機・Suicaを解決 引数を渡して起動 Test commandを構築 Runner・実機をロック 実機の接続を確認 1つのTest processを同期実行 ENABLE_CHARGE_TEST=1 CHARGE_AMOUNT=500 SUICA_ID= xcodebuild test -scheme SuicaApp -destination id=<実機のudid> -only-testing:…/chargeSucceeds Android ENV CMD ANDROID_SERIAL=<実機のserial> ./gradlew connectedChargeTest -P…class=…ChargeSuccessTest -P…enableChargeTest=true -P…chargeAmount=500 -P…suicaId= 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 110 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 111

Slide 111 text

GitHub Actionsで実機テスト実行 on: workflow_dispatch テストシナリオを選択 jobs: 111 verify plan execute GitHub-hosted GitHub-hosted Self-hosted Kotlin製CLIを検証 Target・実機・Runnerを解決 実機でテストを実行 設定schema・シナリオ解決・ Test command構築が、既存の 契約を壊していないか確認する テストシナリオから executionを展開し、どこで 何を実行するかを確定する planが決めたexecutionを、 対応する実機の前で 1件ずつ実行する Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 112

Slide 112 text

workflow_dispatch 実行するテストシナリオだけを指定する 1 workflow_dispatch: inputs: scenario: description: 実行するテストシナリオ required: true type: choice options: - sf-charge.registered-card.success 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 112 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 113

Slide 113 text

jobs.verify Kotlin製CLIのロジックを検証 1 verify: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6 - uses: ./.github/actions/setup-java-gradle - run: ./gradlew :tools:suica-device-test:check 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 113 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 114

Slide 114 text

jobs.plan CLIを準備する1 plan: needs: verify runs-on: ubuntu-24.04 outputs: execution_matrix: ${{ steps.plan.outputs.execution_matrix }} steps: - uses: actions/checkout@v6 - uses: ./.github/actions/setup-java-gradle - run: ./gradlew :tools:suica-device-test:installDist 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 114 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 115

Slide 115 text

jobs.plan シナリオから実行環境を特定する1 - id: plan env: SCENARIO: ${{ inputs.scenario }} run: | matrix="$( tools/suica-device-test/dispatch.sh plan \ --scenario "$SCENARIO" )" echo "execution_matrix=$matrix" >> "$GITHUB_OUTPUT" 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 115 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 116

Slide 116 text

jobs.execute JobとRunnerを決める1 execute: needs: plan strategy: fail-fast: false matrix: ${{ fromJSON(needs.plan.outputs.execution_matrix) }} name: Execute ${{ matrix.execution }} runs-on: ${{ matrix.runner_labels }} 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 116 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 117

Slide 117 text

strategy.matrix の一般的な仕様例 Job定義を値ごとに展開するGitHub Actionsの標準機能 strategy: matrix: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} 117 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 118

Slide 118 text

execution_matrix planの出力をiOS・AndroidのJobへ展開1 { "include": [ { "execution": "ios", "runner_labels": ["self-hosted", "macOS", "ARM64", "hayabusa"] }, { "execution": "android", "runner_labels": ["self-hosted", "macOS", "ARM64", "hayabusa"] } ] } 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 118 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 119

Slide 119 text

jobs.execute Runner上でCLIを準備する1 steps: - uses: actions/checkout@v6 - uses: ./.github/actions/setup-java-gradle - run: ./gradlew :tools:suica-devicetest:installDist 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 119 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 120

Slide 120 text

jobs.execute シナリオと実行定義をCLIへ渡す1 - name: Execute device test env: SCENARIO: ${{ inputs.scenario }} EXECUTION: ${{ matrix.execution }} run: | tools/suica-device-test/dispatch.sh run \ --scenario "$SCENARIO" \ --execution "$EXECUTION" \ --execute 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 120 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 121

Slide 121 text

実機自動テストCIの全体像 設定ファイル GitHub-hosted scenarios.yml workflow̲dispatch → verify → plan テスト内容・固定Target dispatch.sh plan が設定を読み、実行計画を決める inventory.yml execution̲matrix(2要素) 実機・Suica・Runner Self-hosted secrets.env 識別情報の実値 121 execute(ios) execute(android) dispatch.sh run dispatch.sh run 秘密情報・ロック・接続確認 秘密情報・ロック・接続確認 xcodebuild Gradle iPhone端末 + Suica Android端末 + Suica Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 122

Slide 122 text

iOS実機の機能テスト 122 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 123

Slide 123 text

TestEnvironment 環境変数をテスト用の型へ集約 1 enum TestEnvironment { static var isChargeTestEnabled: Bool { ProcessInfo.processInfo.environment[ "ENABLE_CHARGE_TEST" ] == "1" } static var targetSuicaID: String { /* SUICA_IDの取得・検証は省略 */ } static var chargeAmount: Int { /* ... */ } } 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 123 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 124

Slide 124 text

ChargeDeviceTests 本番実装を明示設定して使用(設定処理は省略) 1 @Suite(.serialized) struct ChargeDeviceTests { @Dependency(\.getSuicasUseCase) var getSuicasUseCase @Dependency(\.getBalanceUseCase) var getBalanceUseCase @Dependency(\.chargeUseCase) var chargeUseCase 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 124 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 125

Slide 125 text

ChargeDeviceTests テストは明示的に有効化した場合のみ実行 1 @Test( // 通常のテスト実行ではスキップ .enabled(if: TestEnvironment.isChargeTestEnabled) ) func chargeSucceeds() async throws { 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 125 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 126

Slide 126 text

ChargeDeviceTests 対象のSuicaを選択1 // 実行環境から対象Suicaとチャージ金額を取得 let suicaID = TestEnvironment.targetSuicaID let amount = TestEnvironment.chargeAmount // 実機内のSuicaからIDが一致する対象を特定 let suicas = try await getSuicasUseCase() let suica = try #require( suicas.first { $0.id == suicaID } ) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 126 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 127

Slide 127 text

ChargeDeviceTests チャージを実行(状態復帰の後処理は省略)1 let before = try await getBalanceUseCase(suica) try await chargeUseCase( // ← チャージを実行! suica: suica, amount: amount ) let after = try await getBalanceUseCase(suica) #expect(after - before == amount) 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 127 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 128

Slide 128 text

実機テストの依存グラフ 1 Swift Test @Dependency(\.chargeUseCase) ChargeUseCase(本番実装) 本番実装を明示設定(設定は省略) 本番実装の依存グラフ(接続先は開発環境) API Client 実際のチャージ要求 3DS Bridge WKWebViewで認証 DataSource PassKitをラップし、実機上のSuica・残高・状態を取得 CIでの無人完了条件は未確定 1. 資料用に編集しており、実際の構成を正確に表しているものではありません ↩︎ 128 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 129

Slide 129 text

実機テストでは状態復帰も設計する – 実機ではクリーンな初期状態を毎回作れない – テストで生じた変化を後処理で元に戻す – 新規発行 → 退会払戻でSuicaを削除 – チャージ → 残高を引き去って元に戻す 129 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 130

Slide 130 text

目次 1. Suicaアプリ(仮称)について 2. アーキテクチャ設計 3. テスト戦略 4. 実機自動テストCIの構築 5. まとめ 130 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 131

Slide 131 text

実機自動テストは3つの設計で支える アーキテクチャ テスト戦略 CI運用 View / StateHolder UseCase Repository / DataSource KMPに限らず レイヤーで責務を分け 単体でテストできる構造にする 131 単体テスト 実機テスト 各レイヤーを単体テストし 実機機能テストはSwift Testingから 実行する構成を目指す 物理実機と端末内の状態を テスト環境として管理する Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 132

Slide 132 text

今後の運用課題 – 端末・Suicaの状態管理 – 開始条件の自動確認 – 自動復帰できない場合の対応 – 複数端末での並列実行 – OSバージョンごとの端末確保 – 端末の充電・保守 132 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 133

Slide 133 text

普段のテスト設計を土台に 実機テストもCIで実行! 133 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 134

Slide 134 text

JR東日本でのモバイル開発に 興味があれば、ぜひ声をかけてください! 134 Copyright © 2026 East Japan Railway Company. All rights reserved.

Slide 135

Slide 135 text

ご清聴ありがとう ございました! 135 Copyright © 2026 East Japan Railway Company. All rights reserved.