自作のボードゲームアプリで、画面を本当に押して遊べるかを確かめたいと考えました。ところが、AIにシミュレータを操作させる方法は、権限が足りずに使えませんでした。この記事では、代わりに選んだ「UIテスト」で何が分かり、どんな不具合が見つかったかを書きます。
作りたかったもの
私が作っているのは、iOS のボードゲームアプリです。中には3つのゲームが入っています。
- きえるまるばつ:まるばつゲームで、4個目の駒を置くと一番古い駒が消える遊び方です。
- ふつうのまるばつ:駒が消えない、いつものまるばつゲームです。
- マインスイーパー:旗を立てながら、地雷のないマスを開けていくゲームです。
まるばつの2つは、ふたりで対戦するか、CPU と対戦するかを選べます。CPU の強さは2段階です。
これまでは、ゲームの中の計算が正しいかどうかを確かめるテストしかありませんでした。今回やりたかったのは、もっと人に近い確かめ方です。タイトル画面からゲームを選び、盤のマスを押し、勝ち負けの表示が出るか。最後に「もういっかい」を押して、また遊べるか。こうした一連の操作を、実際の画面で確かめたいと考えました。
AIへの頼み方
作業は Claude Code に任せました。確かめてほしいことは、次のように並べて頼みました。
- 駒を置けるか、4個目で古い駒が消えるか
- 勝ち・負け・引き分けの表示が出るか
- 「もういっかい」で最初から遊べるか
- CPU が考えている途中で、前の画面に戻れるか
- BGM(背景に流れる音楽)が重ならないか
- VoiceOver(画面の内容を声で読み上げる、iPhone の機能)でどう読まれるか
最初は、Claude Code にシミュレータ(Mac の中で iPhone の画面を動かすソフト)を操作させるつもりでした。しかし、Mac のアクセシビリティの権限(ほかのアプリを操作するための許可)がなく、自動で操作できませんでした。
そこで、方法を UIテストに切り替えました。UIテストは、テスト用のプログラムがアプリの画面を探して押し、表示を確かめる仕組みです。Apple の資料では、UIテストはアプリの内部に触れずに、利用者と同じやり方で画面を操作すると説明されています。iOS では XCUITest と呼ばれ、Xcode(Apple のアプリ開発ソフト)に入っています。
Claude Code は、UIテストはシミュレータの中で動くので、Mac の権限が要らないと判断しました。もう一つの利点は、テストが残り続けることです。一度書けば、あとで直したときにも同じ操作を何度でも試せます。
つまずいたところ
押しても何も起きないマス
最初にテストを動かしたとき、19件のうち2件が失敗しました。どちらも、押せないマスを押したときの案内を確かめるテストです。
- 駒が置いてあるマスを押すと「そこには もう こまが あるよ」と出るはず
- 次に消える予定の駒を押すと「その こまは つぎに きえるよ」と出るはず
調べると、テストではなくアプリ側の不具合でした。盤を描く部分が、駒が置いてあるマスのボタンを「押せない状態」にしていたのです。押せない状態のボタンは、押されても何も伝えません。そのため、ゲームの判断をする部分まで操作が届いていませんでした。
結果として、この2つの案内は一度も表示されていませんでした。間違えたときに鳴らすはずの音も、一度も鳴っていませんでした。
これまでのテストで気づけなかった理由
これまでのテストは、ゲームの判断をする部分に、直接「このマスが押された」と伝えていました。画面のボタンを通らないので、ボタンが押せない状態でも、テストは通ってしまいます。
次の図は、2種類のテストが操作をどこから入れているかの違いです。
flowchart LR A["UIテスト"] --> B["画面のボタン"] B -- "押せない状態だと止まる" --> X["何も起きない"] B -- "押せる状態" --> C["ゲームの判断をする部分"] D["これまでのテスト"] --> C C --> E["案内の表示・音"]
これまでのテストは、ボタンを飛ばして直接判断の部分を呼んでいました。だから、ボタンで止まっていることに気づけませんでした。
テスト側の探し方の間違い
途中では、「ふたりで あそぶ」のボタンが見つからない、という失敗もありました。こちらはアプリではなく、テスト側の探し方の問題でした。
SwiftUI(画面を作るための Apple の仕組み)は、ボタンの中に文字の部品が1つだけあると、その文字をボタンそのものの名前として扱います。そのため、ボタンはテストが探していたのとは違う形で画面に現れていました。「文字」として現れる形と「ボタン」として現れる形の両方で探すように、テストを直しました。
失敗したときに、テストが悪いのか、アプリが悪いのかを分けて考える必要がありました。今回は両方が起きています。
どう判断したか
マスは押せるままにして、判断はゲーム側に任せる
不具合の直し方は、駒が置いてあるマスも押せるままにすることでした。押していいかどうかは、画面ではなくゲームの判断をする部分が決めます。こうすると、押してはいけないマスを押したときに、案内と音をきちんと出せます。
マスに名前を付け、読み上げに場所を入れる
テストがマスを確実に押せるように、マスごとに名前を付けました。SwiftUI では accessibilityIdentifier という設定で付けます。Apple の資料では、テストのための値で、利用者には見えないと説明されています。
あわせて、VoiceOver の読み上げに場所を入れました。たとえば「1だんめ 2れつめ」のように読まれます。これまでは「あき」「とじている」が並ぶだけで、どのマスの話か分かりませんでした。
テストに書かなかったもの
19件ですべてを確かめようとはしませんでした。書かなかったのは次のものです。
- 勝ち方や CPU の強さ、地雷の置き方を、すべての場合について確かめること
- 画面の位置(座標)を指定して押すこと
- 決まった秒数だけ待つこと
- 画面の写真を前と比べること
その代わりに、上で書いたとおりマスに名前を付けました。これで、画面の位置ではなく名前でマスを押せます。
テストの記録を本番と分ける
テストのときは、起動のときに渡す設定(起動引数)で、遊んだ記録を端末に残さないようにしました。テストを何度動かしても、前の結果が次のテストに混ざらないようにするためです。
できたもの
UIテストは19件、4つのまとまりに分けて書きました。
- 画面の移り変わり:3つのゲームで、タイトル→選択→対局→戻る、が動くか。マインスイーパーは対戦相手ではなく盤の大きさを選ぶか。CPU が考えている途中で戻れるか。
- きえるまるばつ:交互に置けるか。4個目で一番古い駒が消えるか。消える予定のマスは受け付けないか。勝ちの表示が出るか。「もういっかい」で先に置く人が交代するか。
- ふつうのまるばつ:駒が消えないか。勝ち・引き分けの表示が出るか。「もういっかい」が動くか。
- マインスイーパー:旗の切り替え・設置・解除ができるか。旗のマスは開けられないか。最初の1手で負けないか。「もういっかい」で盤と操作が元に戻るか。
確かめたのは、iPhone 17 Pro のシミュレータです。これまでのテスト103件(11のまとまり。まとまりは、関係するテストを束ねた単位です)と、UIテスト19件(4のまとまり)がすべて通りました。UIテストだけで約5分40秒かかります。
画面が実際に移り変わることを確かめられたのは、今回が初めてでした。
まだ確かめられていないこと
UIテストは、画面の部品の状態を確かめる仕組みです。実際に聞こえる音や声までは確かめられないため、次のものが残りました。
- BGM が重なって流れないか
- VoiceOver が実際にどう読み上げ、読み上げる場所(フォーカス)がどう移るか
- 音がどう聞こえるか
これらは、実機(本物の iPhone)で私が確かめる必要があります。
まとめ
- AIに画面を操作させられないときは、UIテストに書かせる方法があります。権限の問題を避けられ、テストがあとまで残ります。
- これまでのテストが通っていても、画面のボタンで操作が止まっていることがあります。今回は、案内が一度も出ていない不具合がUIテストで見つかりました。
- テストが失敗したら、アプリの不具合かテストの書き方の問題かを分けて考えます。今回は両方がありました。
次は、UIテストでは確かめられない BGM と VoiceOver を、実機で確かめます。
参考にした資料
- User Interface Testing(Apple Developer Documentation Archive)
- accessibilityIdentifier(_:)(Apple Developer Documentation)
- disabled(_:)(Apple Developer Documentation)
この記事は、筆者の開発記録をもとにAI(Claude)が下書きし、筆者が確認して公開しています。