Android APIレベル17から使えそうな、UI Automator Testについて調べてみた(その1)
AndroidのSDKのソースコードを読んでいるときに発見しましたが、
APIレベル16(Jellybean)からは、UIを操作して実行するテストに、新しい方法が追加されるようです。*2
UI Automator Testです。
UI をユーザが操作するテストには、これまでは MonkeyRunner が有りましたが、MonkeyRunnerは、pythonで記述するなど、Javaしか知らないユーザには敷居が高いと言われていました。
# 個人的にはpythonの方が好きなのですが
Javaから、利用する方法もあるには有りましたが、公式な扱いではないため(普通の人がJava での利用法にたどり着くのは)容易ではありません。
今回追加された方法は、Javaのコードを記載することで利用可能です。
また、MonkeyRunnerは、ホスト側のPCと常に通信を行うため、ターゲット側との通信にリソースを取られていました。
しかし、今回追加された方式では、JUnitを使ったテスト同様、端末(ターゲット)にコードを事前に送り込んで実行します。
さて、利用方法を見ていきましょう。
コードレベルの利用方法を記載したドキュメントは、まだありません。
ソースコードを読む必要があります。
また、現状では、Android 全体のソースコードが必要です。
/frameworks/testing/uiautomator/
- cmds : adb shell から実行するためのコマンド
- library: テストフレームワークのライブラリ
- samples: サンプルのスケルトン
- utils : DummyIME(用途不明、おそらくはテスト実行時の際に利用するIME)
ビルドと実行の方法は、samples/SkeletonTest 配下にある README を読んでください。
デフォルトでは、uiautomator はビルドの対象にならないので、
Android のビルド後に以下のコマンドを発行することで、ビルドされます。
mmm frameworks/testing/uiautomator/samples/SkeletonTest
mmm は、Android のビルドの envsetup.sh を読み込むと使えるようになるコマンドです。
上記コマンドを実行することで、「uiautomator.skeletontest.jar」というファイルが生成されます。
これを、ターゲットの /data/local/tmp/ に配置してやり、コマンドを発行することでテストを実行します。
adb push {DROIDROOT}/out/data/local/tmp/uiautomator.skeletontest.jar /data/local/tmp/
adb shell uiautomator runtest uiautomator.skeletontest.jar \
-e class com.android.uiautomator.samples.skeleton.DemoTestCase
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
としてみたところ、以下のようにRuntimeErrorが発生してしまいました。
原因はまだよくわかっていません。
TestCaseを集める所辺りでエラーが起こっているようです。
C:\Users\miyabi\testing>adb shell uiautomator runtest uiautomator.skeletontest.jar -e class com.android.uiautomator.skeletontest.DemoTestCase
INSTRUMENTATION_RESULT: shortMsg=java.lang.RuntimeException
INSTRUMENTATION_RESULT: longMsg=com.android.uiautomator.skeletontest.DemoTestCase
INSTRUMENTATION_CODE: 0
まだ先は長いようです。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
自分でテストケースを作る場合は、上記のスケルトンをコピーしてモジュール名を書き換えてやれば良さそうです。
Android.mkの LOCAL_MODULE_NAME, LOCAL_MODULE_TAGSを書き換えましょう。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
サンプルの解説
サンプルは非常に簡単なもので、以下の操作を再現しているようです。
1.ホームボタンを押し機能したかを確認
2.画面サイズを取得
3.ステータスオブジェクトに文字列を追加し、渡した先のFakeInstrumentWatcher経由でSystem.printlnする。
assertTrue(getUiDevice().pressHome());
Bundle status = new Bundle();
status.putString("msg", "This is a demo test and I just pressed HOME");
status.putString("product", getUiDevice().getProductName());
Point p = getUiDevice().getDisplaySizeDp();
status.putInt("dp-width", p.x);
status.putInt("dp-height", p.y);
getAutomationSupport().sendStatus(Activity.RESULT_OK, status);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
UI Automator Testにて使える関数
UiAutomatorTestCaseは、JUnitのTestCaseの派生の為、JUnit同様のassertが利用可能です。
また、テスト環境にも様々なクラスが用意されています。
その中で、重要そうなクラスをピックアップしてみました。
今後、使い方を模索しながら試してみたいと思います。
- UIDevice : Android端末を意味するオブジェクト、画面サイズやハードウェアキー、クリック(座標系)
- UIObject : Android 上のViewに該当するオブジェクト、クリックなどの操作が可能
- UISelector : Viewを探すための指定子
インデックス(何の?)、含まれているテキストを検索、クラス名、フォーカス、スクロール可能等の指定によって、
Viewを指定可能にする者と思われます。
UIDeviceが、MonkeyDevice 相当の様です。
あまり解説はされてきてませんが、EasyMonkeyDevice 関連の実装で実現しようとしていたことを、
MonkeyViewが、UIObject相当で実現しているようです。
monkeyrunner.easy.By での検索は遅かったので、UISelectorの検索速度に期待したい所です。
# EasyMonkeyDeviceは、HierarchyViewerと連携していたので遅かった・・・のでこれまであまり解説して来ませんでした。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
その他出来ること
adb shell uiautomator には、他にもサブコマンドが用意されています。
events と dump です。
events はユーザが実際にターゲット端末を操作したイベントをホストPCに転送します。
PC側のリッチな環境でイベントの解析を行い、リプレイを行うなどの機構が用意されれば、MonkeyRecorder 同様の操作が可能になります。
また、手動でテストを行う際のエビデンスとしても利用可能です。
また、dump は、Hierarchy Viewerの代替です。
Hierarchy Viewerは、Engineering ビルドをした端末か、エミュレータでしか利用できませんでしたが、
dumpは全ての端末で利用可能になる物と思われます。
# アプリ側で制限がかけられるといいですね。
上記の図のように、Eclipse から実行する機能が追加されており、dumpしたXMLをEclipseが解析することで、
UIの構造を読み取ることが可能です。
adb shell uiautomator dump を実行した場合は、/data/local/tmp/window_dump.xml が生成されます。
# 名前は変えられない模様
# XMLを動的に読み取れば、テストの自動生成が出来るかとも思ったのですが、IDがないため難しそうです。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
気になっている所
Report はどのように通知されるのか。
JUnitのXML形式への変換は行えるのか。
# Jenkins での判別に使えるので
UIAutomatorTestCase自体が、JUnitのTestCaseの派生なので、JUnit のライブラリを弄れば使えそうです。
総括
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
MonkeyRunner同様にUIの操作が可能と思われるAPIが用意されています。
しかしながら、動作しないこととテストの作成にAndroid 自体のビルドを行わねばならぬこと等、まだまだ敷居が高い様です。
継続的に監視します。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
追記:ClassNotFoundなので、ちゃんとロードできてないのが原因?
classpath からなにから追って見る。
E/UiAutomatorTestRunner( 794): uncaught exception
E/UiAutomatorTestRunner( 794): java.lang.RuntimeException: com.android.uiautomator.skeletontest.DemoTestCase
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:98)
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.UiAutomatorTestRunner.run(UiAutomatorTestRunner.java:85)
E/UiAutomatorTestRunner( 794): at com.android.commands.uiautomator.RunTestCommand.run(RunTestCommand.java:76)
E/UiAutomatorTestRunner( 794): at com.android.commands.uiautomator.Launcher.main(Launcher.java:83)
E/UiAutomatorTestRunner( 794): at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
E/UiAutomatorTestRunner( 794): at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:235)
E/UiAutomatorTestRunner( 794): at dalvik.system.NativeStart.main(Native Method)
E/UiAutomatorTestRunner( 794): Caused by: java.lang.ClassNotFoundException: com.android.uiautomator.skeletontest.DemoTestCase
E/UiAutomatorTestRunner( 794): at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:61)
E/UiAutomatorTestRunner( 794): at java.lang.ClassLoader.loadClass(ClassLoader.java:501)
E/UiAutomatorTestRunner( 794): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.TestCaseCollector.addTestClass(TestCaseCollector.java:84)
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.TestCaseCollector.addTestClass(TestCaseCollector.java:72)
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.TestCaseCollector.addTestClasses(TestCaseCollector.java:53)
E/UiAutomatorTestRunner( 794): at com.android.uiautomator.testrunner.UiAutomatorTestRunner.start(UiAutomatorTestRunner.java:95)
E/UiAutomatorTestRunner( 794): ... 6 more
I/AndroidRuntime( 794): VM exiting with result code -1.