


モバイルUI自動化フレームワークを開発し、不具合はCIでなく製品側で直す
クロスプラットフォームのモバイルUI自動化フレームワークをAIに開発させる時に使う。変更を受け持つモジュールに置き、動作を確かめられる一番安いテスト層を選び、必ず通るスイートとわざと失敗させるスイートを分け、CIの設定ではなく製品側で不具合を直す。
このAIルールを使うには
## 変更を、その動作を受け持つモジュールに置く
コードがどこで実行され、生成物を誰が利用するかを示す簡潔なモジュールマップを維持する。少なくとも次の責務を分離する。
- デバイス側ドライバーと、そこから生成されるバイナリ
- ホスト側のプラットフォームアダプターとプロトコルクライアント
- コマンド解釈、再試行、ライフサイクル制御、エラー分類
- 共有コマンドモデルとデータモデル
- コマンドラインおよびエージェント向けインターフェース
- Webドライバー、通信形式の定義、ユーティリティ、モジュール横断テスト
動作を所有する場所へ変更を置く。デバイス操作とシステムダイアログへの対応はプラットフォームドライバーまたはホストアダプター、再試行とコマンド順序の制御はオーケストレーション、共有リクエスト形式はモデルまたはプロトコルのモジュールが担う。離れたモジュールの方が修正しやすいという理由だけで、所有範囲の問題をそこで解決してはならない。
このマップを、workflowと専門エージェントが参照する単一の正本として扱う。モジュールの責務が変わった時は更新し、下流の案内とのずれを防ぐ。
## 動作を確かめられる、一番安いテスト層を選ぶ
階層化したテスト戦略を使い、動作を証明できる範囲で最も低コストな層を既定にする。
1. 独立したクラス、解析、小さなユーティリティ、局所的な判断ロジックには単体テストを使う。
2. デバイスなしで実行できるコマンドのオーケストレーション、キャンセル、スクリプトエンジン、ネットワーク境界、複数モジュールの連携には統合テストを使う。
3. 実ドライバー、デバイスまたはブラウザーの動作、OS統合、完全な利用者フローにはE2Eテストを使う。
4. 製品がAI向けプロトコルを備える場合、モデルの動作とツールの正しさにはエージェントインターフェース評価を使う。
fakeまたはプロセス内コンポーネントで契約を正確に表現できるのに、テストを高コストな層へ引き上げてはならない。反対に、リスクの本体がプラットフォーム動作にある場合は、デバイスレベルの証拠をmockで置き換えてはならない。
## 必ず通るスイートと、わざと失敗させるスイートを分ける
期待する結果ごとにE2Eフローを分ける。正常系スイートには必ず成功すべきフローを置き、失敗はすべて不具合として扱う。異常系スイートには意図的に無効なassertionまたはコマンドを置き、想定した形で失敗しなければならない。
テストハーネスが異常系スイートの成否を反転させる場合があるため、成果物を解釈する時はスイートのラベルを保持する。想定どおりの異常系結果を製品の不具合と診断してはならず、成功させる目的で異常系フローを弱めたり書き換えたりしてはならない。
自動診断処理が成果物を利用する場合、その契約が異常系分析を明示的に扱わない限り、対象を正常系スイートの実際の失敗だけに限定する。成果物は、アプリケーション、プラットフォーム、スイート、実行識別子を含む予測可能な階層へ保存する。
## 1つのfixtureアプリを、全プラットフォームのE2Eテストに使い回す
対応する全プラットフォームでコマンド全体を検証するため、1つの既定fixtureアプリケーションを使う。同じフローを、現行プラットフォーム版での回帰smoke testと、新たに導入するOS版での互換性検証の2つに再利用する。
動作が特定フレームワークに固有なら、既定アプリケーションを不自然に変形せず、専用のfixture workspaceを追加する。各workspaceに固有のフローとbuild artifactを持たせ、手動実行では1つのアプリケーションまたは1つのフローへ対象を絞れるようにする。
テストドライバーはプラットフォームと明示的な環境入力を引数として受け取る設計にする。高コストな基盤を用意する前に実行指定を検証し、未対応のシステムバージョン、存在しないworkspace、曖昧なフロー指定を早期に拒否する。
## デバイスでの失敗を、CIの設定でごまかさずドライバー側で直す
プラットフォームドライバーが実際のデバイス動作を扱えずE2Eフローが失敗した場合は、利用者が実行するドライバー、ホストアダプター、またはfixtureアプリケーションを修正する。CI workflowへemulator設定、shell command、コマンドライン調整、事前構成を追加して不足を隠してはならない。
workflowの変更が適切なのは、matrix、保持期間、trigger、検証済みの実行指定、限定的かつ文書化された基盤上の例外など、workflowの形を扱う場合である。製品動作の代替として使ってはならない。
新しいOS版の検証にも同じ原則を適用する。CI固有の準備を行った時だけフローが成功するなら、その準備が利用者に明示された前提条件でない限り、製品の互換性に問題が残っている。
## エラーを再試行できるかで分け、一時ファイルを必ず片付ける
明示的なdispatcherまたはexecutorを備えた構造化非同期実行を使う。blocking bridgeはアプリケーションのentry pointに限定する。公開される失敗を分類し、すべてを一律に再試行するのではなく、オーケストレーションが再試行可能な状態と終了すべきエラーを区別できるようにする。
一時ファイルと一時ディレクトリは、ライフサイクルを所有するresource managerを経由させる。リソースを所有する処理の近くでmanagerを構築し、そのAPIを通じて割り当て、`finally`経路で閉じる。これにより成功、失敗、キャンセルのいずれでも再帰的な後片付けが行われる。
一時ファイルを直接作成してresource managerを迂回してはならない。管理されないファイルは長時間稼働するworker内に蓄積し、失敗の再現を難しくする。デバイスが不要な場合は、決定的に動くfake driverを使った実際のオーケストレーションで、キャンセル、タイムアウト、supervisor動作、後片付けをテストする。
## エージェント向けのツールと、モデルの動きを別々にテストする
コマンドラインアプリケーションがエージェント向けserverも提供する場合、次の2種類のテストを分けて維持する。
- リクエスト、レスポンス、デバイス設定、失敗時の動作を検証するツール機能テスト
- エージェントが適切なツールを選択して使用できるかを測るモデル動作評価
宣言的な評価ケースとプラットフォーム固有の設定スクリプトを使い、対象範囲を再現可能にする。通常の実装変更では高速なツールテストを実行し、prompt、ツール説明、schema、routing、エージェントに見える動作を変更した場合は、より時間のかかるモデル評価を実行する。
モデルのscoreを基礎となるツールが動作する証拠として扱ってはならず、ツール機能テストをエージェントが正しく使える証拠として扱ってもならない。2つの契約には、それぞれ固有の証拠が必要である。
## 生成されたバイナリは手で直さず、ビルドで作り直す
リポジトリに格納されたドライバーバイナリ、パッケージ化されたrunner、checksum、その他の派生成果物は、generatorが作るものとして扱う。手作業で編集してはならない。所有元のbuild taskまたはfinalizerを実行し、生成したsource変更と派生成果物を一緒にcommitする。
完了前に次を確認する。
1. 動作を所有するモジュールに変更が置かれている。
2. 成立する最も低いテスト層を実行し、直接影響する上位層も実行した。
3. 正常系と異常系のスイートを、それぞれの契約に従って解釈した。
4. 成功、失敗、キャンセルのいずれでも一時リソースが閉じられることを検証した。
5. 公式のbuild経路で派生成果物を再生成した。
6. CI変更が製品の不具合を隠すものではなく、基盤の形を表していることを確認した。
workflow文書、fixture配置、モジュール所有範囲の注記を同期し、後続の開発者と自動エージェントが同じ境界に従えるようにする。
