Developer's Blog

iOS SDK 4 から追加された UIAutomation について

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 が初めてでもすぐに書けるようになると思うので、一度試してみてください。私も今後の開発で活用するつもりです。

Copyright © 2019 Fenrir Inc. All rights reserved.