0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

テストは全部通ったのに、アプリは壊れていた:Optics Framework のエラー定義で「最後の画面」を検査する

0
Posted at

筆者は Optics Framework の開発に関わっています。この記事のコマンドと出力は、Optics Framework 1.11.0(macOS、Python 3.12)で実際に実行したものです。

よくある「緑なのに壊れている」問題

カートに商品を入れるテストを考えます。サインインし、商品を開き、カートに追加し、「Added to cart」が表示されることを確認する。すべてのステップが通ります。

ところが、最後の画面には「Your session expired. Please sign in again.」と出ている。前夜のビルドでトークンの更新が壊れていたのですが、テストは「Added to cart」しか見ていないので、CI は緑のままです。

エラー画面は、どこに出るか予測できません。Android の「〇〇が停止しました」ダイアログ、「応答していません」、「Something went wrong」のページ、オフラインのバナー。全ステップの後にすべてをアサートすれば、テストは倍に膨れ上がり、それでも次に追加されるメッセージは見逃します。

エラー定義ファイル

Optics Framework には、この問題のための「エラー定義」という機能があります。「これが出たら異常」というメッセージを CSV に並べておくと、実行の最後に画面を読んで、どれかが出ていないかを調べます。

プロジェクト内の任意の場所に、次のような CSV を置きます。

error_definitions.csv
error_code,match_string,description,severity
ERR_CRASH,has stopped,The app crashed,critical
ERR_SESSION,Session expired,The user was signed out,high
ERR_SERVER,Something went wrong,Server error page,high
  • match_string:画面上で探す文字列
  • error_code:レポートに出る短い名前
  • description、severity:任意。レポートにそのまま書き出されます

error_code と match_string の列があれば、Optics Framework がエラー定義ファイルだと判断します。設定やキーワードの追加は不要で、optics execute のたびに使われます。

実際に試す

「Added to cart」と、セッション切れのバナーが両方出るページを用意しました。

site/cart.html
<h1>Birch Shop</h1>
<p>Added to cart</p>
<div class="banner">Your session expired. Please sign in again.</div>

テストは「Added to cart」があることだけを確認します。

modules/modules.csv
module_name,module_step,param_1,param_2
Open Cart,Launch App,file:///path/to/site/cart.html
Check Cart,Assert Presence,${added}
test_data/elements.csv
Element_Name,Element_ID
added,text=Added to cart

実行すると、テスト自体は通ります。

└── TC1 Add To Cart                                      |      0.98s |    PASS
    ├── Open Cart                                        |      0.85s |    PASS
    │   └── Launch App (file:///...)                     |      0.84s |    PASS
    └── Check Cart                                       |      0.13s |    PASS
        └── Assert Presence (text=Added to cart)         |      0.13s |    PASS
│ Total Test Cases: 1 | Passed: 1 | Failed: 0                                  │

一方で、execution_output/execution_logs.log には警告が出ています。

WARNING - ON-SCREEN ERROR DETECTED — code: ERR_SESSION | matched_on: match_string | match_string: 'Session expired' | severity: high | The user was signed out

そして execution_output/detected_errors_<セッションID>.json が作られます。

{
  "timestamp": "2026-10-20T18:29:06.472038+05:30",
  "detected": [
    {
      "error_code": "ERR_SESSION",
      "matched_on": "match_string",
      "match_string": "Session expired",
      "description": "The user was signed out",
      "severity": "high",
      "detected_at": "end_of_run"
    }
  ]
}

マッチは大文字・小文字を区別せず、部分一致です。Session expired で「Your session expired. Please sign in again.」も拾えています。

どのテキストを読んでいるか

チェックには OCR を使わず、ドライバーがすでに持っている UI ツリーを読みます。Web ではタグを取り除いた、画面に見えるテキストだけを対象にします。Android・iOS では text、content-desc、label、value、hint、name 属性です。

id や class 名は見ないので、上の例の class="banner" や、id="error_retry" のようなボタンで誤検知することはありません。コストは、実行の最後のページソース取得 1 回分だけです。

CI を落とす

JSON ファイルはエラーが見つかったときにしか作られません。なので、スイートの後に「ファイルがあれば失敗」というステップを 1 つ足せば、CI を赤にできます。

.github/workflows/e2e.yml
- name: Run the suite
  run: optics execute birch-tests
- name: Fail on error screens
  run: |
    if compgen -G "birch-tests/execution_output/detected_errors_*.json" > /dev/null; then
      cat birch-tests/execution_output/detected_errors_*.json
      exit 1
    fi

ジョブのログに、どのエラーコードとメッセージが出ていたかが表示されるので、スクリーンショットを開かなくても原因がわかります。古い execution_output が残っていると前回のファイルを拾ってしまうので、クリーンなチェックアウトで実行してください。

match_string の選び方

  • エラーのときにしか出ない言い回しを選ぶ。「has stopped」は良い例で、「Error」は広すぎます(エラーについてのヘルプページにも当たります)。
  • エラー画面のスクリーンショットから正確な文言をコピーし、短くする。マッチは単純な文字列比較なので、* や .* はその文字そのものとして扱われます。
  • アプリが意図的に表示する文言は入れない。最後の画面のどこかに出ていれば当たってしまいます。

注意点

  • チェックするのは「実行が終わった時点の画面」です。Suite Teardown でアプリを閉じていると読む画面がなくなるので、閉じるステップは teardown から外してください。
  • フローの途中で一瞬だけ出るメッセージは拾えません。途中の画面は、次に期待する画面をアサートして確認します。
  • Python や Robot Framework から使う場合は、Add Error Definitions を一度呼び、好きなタイミングで Capture And Detect を呼べば、テストの途中でもチェックできます。

なぜ便利か

既存のテストを 1 行も変えずに、すべてのテストにこのチェックが付きます。1 つの CSV で Android・iOS・Web・TV の実行をカバーでき、サポート窓口が新しいエラーを見つけたら、行を 1 つ足してプルリクエストでレビューするだけです。

インストールと最初のテストは、Zenn の記事 にまとめています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?