iOS SDK 4 から追加された UIAutomation について調べてみました。
UIAutomation を使えば、JavaScript で UI の自動テストが可能になります。Instruments 上でターゲットのアプリと JavaScript のファイルをつなぐと実行できます。
詳しい導入方法はドキュメントを見てもらうとして、何ができるかをまとめてみました。
何ができるのか
- ログを出す
- 通常のログ出力
- 成功と失敗用のログ出力があって、それでテスト結果を判定する
- スクリーンショットをとる
- 画面全体または一部のスクリーンショットを撮影できる
- エラーの検知
- クラッシュなどがおきると JavaScript の例外がくる
- タップなどのユーザーのアクション
- ボタンなどの UI エレメントやデバイスに対して実行できる
- ドラッグ、フリック、ピンチイン、ピンチアウトなども可能
- UI の状態を取得
- 状態があっているかをテストする
- テキストの値や、有効状態を取得できる
- 回転ロックやボリュームコントロールのイベント
- 端末の回転
- UIDeviceOrientation と同じ6種類の get と set ができる
- マルチタスキング
- アプリをバックグラウンドにもっていける
- 設定
- ユーザデフォルトの値を設定できそう(未確認)
細かいできることはまだまだありますが、ざっとこんな感じです。UI 要素をたどるのが面倒なだけで、ユーザーのアクションはほぼ実現できそうです。
次に、実際のコードの書き方を紹介します。
まず最初に書く
// script の開始時に記述 UIALogger.logStart("テストの開始"); // 長くて面倒なので、初めに書いておく var target = UIATarget.localTarget(); // デバイス (UIATarget) var app = target.frontMostApp(); // アプリ (UIAApplication) var window = app.window(); // Window (UIAWindow)
ログを用いてテスト関数を書く
//テストに失敗 (Instruments で赤色に) UIALogger.logFail("Failed"); //テストに成功(Instrumentsで緑色に) UIALogger.logPass("Success");
次のようなテスト関数を書いていけば、どのテストに失敗したか一目でわかるはず。
function testAdd() { UIALogger.logMessage("testAddスタート"); try { ... if (...) { UIALogger.logPass("OK"); } else { UIALogger.logFail("testAdd 失敗"); } UIALogger.logPass("testAdd 成功"); } catch (e) { // 例外 UIALogger.logFail("testAdd 失敗"); } }
UIAElement をたどる
UIAutomation で UI 要素は UIAElement クラスとして定義されており、だいたいの UIView のサブクラスは 対応する UIAElement のサブクラスがあります。ただ、UIAWebView の Webページ自体も UIAElement で表現されていたりと少し UIKit とは違う構造になっているようです。UIAWindowが一番親なので、そこから子要素をたどっていって目的の UI 要素にアクセスします。
// これらは Window に属する var statusBar = window.statusBar(); var tabBar = window.tabBar(); var naviBar = window.navigationBar(); var toolbar = window.toolbar(); // 1つ下の階層のUIAElementたちがUIAElementArrayで返る var w_elems = window.elements(); var elem = w_elems[0]; var elems = element.elements(); // あるUIAElementクラスだけのUIAElementArray var buttons = elem.buttons(); var images = elem.images(); // タップ buttons[0].tap(); // ドラッグ buttons[0].dragInsideWithOptions({startOffset:{x:0.0, y:0.5}, endOffset:{x:1.0, y:0.5}, duration:2.0});
スクリーンショットをとる
エラーが起きた時などに撮影しておけば、原因究明に役立ちます。
var rect = { origin: {x:100, y:200}, size: {width:100, height:100} }; target.captureRectWithName("imageName", rect); // 画面全体 target.captureScreenWithName("imageName");
端末の回転
iOS SDK の 6つの UIDeviceOrientation に設定できます。細かい傾きの指定などはできないようです。
target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT); UIALogger.logMessage("向きをLandscaleLeftに"); /* LandscapeLeftの状態でテスト */ ... */ // 他のテストに影響を与えないように PORTRAIT に戻す target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_PORTRAIT); UIALogger.logMessage("向きをPortraitに");
コントロール類
target.lock(); target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_PORTRAIT); // 確かに回転しない target.unlock(); target.clickVolumeUp(); target.holdVolumeUp(); target.clickVolumeDown(); target.holdVolumeDown();
マルチタスキング
UIALogger.logMessage("Deactivating app"); target.deactivateAppForDuration(10); // 10秒間バックグラウンドにいく UIALogger.logMessage("Resuming test");
基本的にユーザーのタップを実現するだけなので、JavaScript のコードは単純です。JavaScript が初めてでもすぐに書けるようになると思うので、一度試してみてください。私も今後の開発で活用するつもりです。