monkeyrunner

monkeyrunner ツールは、Android コードの外部から Android デバイスまたはエミュレータを制御するプログラムを作成するための API を提供します。monkeyrunner を使用すると、Android アプリまたはテスト パッケージのインストールと実行、キー操作の送信、ユーザー インターフェースのスクリーンショット取得、取得したスクリーンショットのワークステーションへの保存を行う Python プログラムを作成できます。monkeyrunner ツールは機能 / フレームワーク レベルでアプリとデバイスのテストを行い、単体テストスイートを実行することを主な目的として設計されていますが、それ以外の目的でも自由に使用できます。

monkeyrunner ツールは、UI/Application Exerciser Monkey(別名 monkey ツール)とは関係ありません。monkey ツールは、デバイスまたはエミュレータ上の adb シェル内で直接実行され、ユーザー イベントとシステム イベントの擬似ランダム ストリームを生成します。これに対して、monkeyrunner ツールは API から特定のコマンドとイベントを送信することで、ワークステーションからデバイスとエミュレータを制御します。

monkeyrunner ツールには、Android のテストを行うための以下のような独自の機能があります。

  • 複数のデバイスの制御: monkeyrunner API は、複数のデバイスまたはエミュレータに 1 つ以上のテストスイートを適用できます。一度にすべてのデバイスを物理的に接続するかすべてのエミュレータを起動し(またはその両方)、プログラムで順番に接続して、複数のテストを実行できます。また、エミュレータの構成をプラグラムで起動して、複数のテストを実行し、エミュレータをシャットダウンすることもできます。
  • 機能テスト: monkeyrunner は、Android アプリの起動から終了までを自動化してテストできます。キー操作またはタッチイベントの入力値を渡すと、結果がスクリーンショットとして表示されます。
  • 回帰テスト: monkeyrunner では、アプリを実行し、出力されたスクリーンショットと正常とされているスクリーンショットを比較することで、アプリの安定性をテストできます。
  • 拡張可能な自動化: monkeyrunner は API ツールキットであるため、Python ベースのモジュールとプログラムのシステム全体を開発して、Android デバイスを制御できます。monkeyrunner API 自体を使用する以外に、標準の Python os モジュールと subprocess モジュールを使用して、Android Debug Bridge などの Android ツールを呼び出すこともできます。

    また、monkeyrunner API に独自のクラスを追加することもできます。詳細については、プラグインを使用して monkeyrunner を拡張するのセクションをご覧ください。

monkeyrunner ツールは、Java プログラミング言語を使用した Python の実装である Jython を使用しています。そのため、monkeyrunner API では Android フレームワークと簡単にやり取りできます。Jython では、Python 構文を使用して、API の定数、クラス、メソッドにアクセスできます。

シンプルな monkeyrunner プログラム

デバイスに接続して MonkeyDevice オブジェクトを作成する簡単な monkeyrunner プログラムを以下に示します。このプログラムは、MonkeyDevice オブジェクトを使用して Android アプリ パッケージをインストールし、そのアクティビティの 1 つを実行してキーイベントをアクティビティに送信します。次に、プログラムは結果のスクリーンショットを取得し、MonkeyImage オブジェクトを作成します。そして、このオブジェクトから、スクリーンショットを含む .png ファイルを出力します。

    # Imports the monkeyrunner modules used by this program
    from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice

    # Connects to the current device, returning a MonkeyDevice object
    device = MonkeyRunner.waitForConnection()

    # Installs the Android package. Notice that this method returns a boolean, so you can test
    # to see if the installation worked.
    device.installPackage('myproject/bin/MyApplication.apk')

    # sets a variable with the package's internal name
    package = 'com.example.android.myapplication'

    # sets a variable with the name of an Activity in the package
    activity = 'com.example.android.myapplication.MainActivity'

    # sets the name of the component to start
    runComponent = package + '/' + activity

    # Runs the component
    device.startActivity(component=runComponent)

    # Presses the Menu button
    device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)

    # Takes a screenshot
    result = device.takeSnapshot()

    # Writes the screenshot to a file
    result.writeToFile('myproject/shot1.png','png')
    

monkeyrunner API

monkeyrunner API は、com.android.monkeyrunner パッケージの 3 つのモジュールに含まれています。

  • MonkeyRunner: monkeyrunner プログラムのユーティリティ メソッドのクラス。このクラスは、monkeyrunner をデバイスまたはエミュレータに接続するためのメソッドを提供します。また、monkeyrunner プログラム用 UI の作成と、組み込みヘルプの表示を行うためのメソッドも提供します。
  • MonkeyDevice: デバイスまたはエミュレータを表します。このクラスは、パッケージのインストールとアンインストール、アクティビティの開始、キーボード イベントまたはタッチイベントのアプリへの送信のためのメソッドを提供します。また、このクラスを使用してテスト パッケージを実行することもできます。
  • MonkeyImage: スクリーン キャプチャの画像を表します。このクラスは、スクリーンのキャプチャ、さまざまな形式へのビットマップ イメージの変換、2 つの MonkeyImage オブジェクトの比較、ファイルへのイメージの書き出しを行うためのメソッドを提供します。

Python プログラムでは、各クラスに Python モジュールとしてアクセスします。monkeyrunner ツールでは、こうしたモジュールが自動的にインポートされることはありません。モジュールをインポートするには、Python の from ステートメントを使用します。

    from com.android.monkeyrunner import <module>
    

ここで、<module> はインポートするクラス名です。モジュール名をカンマで区切ることで、1 つの from ステートメントで複数のモジュールをインポートできます。

monkeyrunner を実行する

monkeyrunner プログラムを実行するには、ファイルから実行するか、対話型セッションの形式で monkeyrunner ステートメントを入力します。どちらも、SDK ディレクトリの tools/ サブディレクトリにある monkeyrunner コマンドを呼び出すことで行うことができます。引数としてファイル名を指定した場合、monkeyrunner コマンドはファイルの内容を Python プログラムとして実行します。それ以外の場合は、対話型セッションが開始されます。

monkeyrunner コマンドの構文は以下のとおりです。

    monkeyrunner -plugin <plugin_jar> <program_filename> <program_options>
    

フラグと引数については表 1 を参照してください。

表 1. monkeyrunner フラグと引数。

引数 説明
-plugin <plugin_jar> (任意)monkeyrunner のプラグインを含む .jar ファイルを指定します。monkeyrunner のプラグインの詳細については、プラグインを使用して monkeyrunner を拡張するをご覧ください。複数のファイルを指定する場合は、引数を複数指定します。
<program_filename> この引数を指定すると、monkeyrunner コマンドはファイルの内容を Python プログラムとして実行します。引数が指定されていない場合、コマンドは対話型セッションを開始します。
<program_options> (任意)<program_file> 内のプログラムのフラグと引数。

monkeyrunner の組み込みヘルプ

以下を実行することで、monkeyrunner の API リファレンスを生成できます。

    monkeyrunner help.py <format> <outfile>
    

引数は以下のとおりです。

  • <format> には、書式なしテキストを出力する場合は text、HTML を出力する場合は html を指定します。
  • <outfile> には、出力ファイルの修飾パス名を指定します。

プラグインを使用して monkeyrunner を拡張する

Java プログラミング言語で書かれたクラスで monkeyrunner API を拡張し、1 つ以上の .jar ファイルに組み込むことができます。この機能を使用して、独自のクラスによる monkeyrunner API の拡張や既存のクラスの拡張を行うことができます。また、monkeyrunner 環境の初期化もできます。

monkeyrunner にプラグインを組み込むには、表 1 で説明した -plugin <plugin_jar> 引数を付けて、monkeyrunner コマンドを呼び出します。

プラグインのコードでは、com.android.monkeyrunner 内にある monkeyrunner のメインクラス、MonkeyDeviceMonkeyImageMonkeyRunner をインポートまたは拡張できます(monkeyrunner API を参照)。

プラグインでは Android SDK にアクセスできず、com.android.app などのパッケージをインポートできないため、注意してください。これは、monkeyrunner がフレームワーク API レベル以下でデバイスまたはエミュレータとやり取りするためです。

プラグイン起動クラス

プラグインの .jar ファイルでは、スクリプト処理の開始前にインスタンス化されるクラスを指定できます。このクラスを指定するには、MonkeyRunnerStartupRunner キーを .jar ファイルのマニフェストに追加します。値は、起動時に実行するクラスの名前である必要があります。次のスニペットは、ant ビルド スクリプト内でこれを行う方法を示しています。

    <jar jarfile="myplugin" basedir="${build.dir}">
    <manifest>
    <attribute name="MonkeyRunnerStartupRunner" value="com.myapp.myplugin"/>
    </manifest>
    </jar>

    

monkeyrunner のランタイム環境にアクセスするには、起動クラスで com.google.common.base.Predicate<PythonInterpreter> を実装します。たとえば、次のクラスでは、デフォルトの名前空間にいくつかの変数を設定しています。

Kotlin

    package com.android.example

    import com.google.common.base.Predicate
    import org.python.util.PythonInterpreter

    class Main: Predicate<PythonInterpreter> {

        override fun apply(anInterpreter: PythonInterpreter): Boolean {
            /*
             * Examples of creating and initializing variables in the monkeyrunner environment's
             * namespace. During execution, the monkeyrunner program can refer to the variables
             * "newtest" and "use_emulator"
             *
             */
            anInterpreter.set("newtest", "enabled")
            anInterpreter.set("use_emulator", 1)
            return true
        }
    }
    

Java

    package com.android.example;

    import com.google.common.base.Predicate;
    import org.python.util.PythonInterpreter;

    public class Main implements Predicate<PythonInterpreter> {
        @Override
        public boolean apply(PythonInterpreter anInterpreter) {

            /*
            * Examples of creating and initializing variables in the monkeyrunner environment's
            * namespace. During execution, the monkeyrunner program can refer to the variables "newtest"
            * and "use_emulator"
            *
            */
            anInterpreter.set("newtest", "enabled");
            anInterpreter.set("use_emulator", 1);

            return true;
        }
    }