UI Automator で自動テストを作成する

UI Automator は、アプリ間の機能 UI に適した UI テスト フレームワークです システムやインストール済みのアプリをテストできます。UI Automator API を使用すると どの Activity が含まれるかにかかわらず、デバイス上で可視要素を含む [設定] メニューを開くなどの操作ができるようになります。 またはテストデバイスのアプリ ランチャーで確認できます。テストで UI コンポーネントを検索するには、 コンポーネントに表示されるテキストやそのコンポーネントに 作成します。

UI Automator テスト フレームワークはインストルメンテーション ベースの API であり、 AndroidJUnitRunner テストランナーを使用します。文章を書くのに 不透明なボックススタイルの自動テスト。テストコードは内部の ターゲット アプリの実装の詳細。

UI Automator テスト フレームワークの主要な機能は次のとおりです。

で確認できます。

デバイスの状態にアクセスする

UI Automator テスト フレームワークには、アクセスするための UiDevice クラスが用意されています。 ターゲット アプリが実行されているデバイスで操作を実行できます。Google Chat では そのメソッドを呼び出して、デバイスのプロパティ(画面の向き、 指定します。UiDevice クラスでは、次のこともできます。 アクション:

  1. デバイスの回転を変更する。
  2. ハードウェア キー(「音量大」など)を押す。
  3. 「戻る」ボタン、ホームボタン、メニューボタンをクリックする。
  4. 通知シェードを開く。
  5. 現在のウィンドウのスクリーンショットを撮る。

たとえば、ホームボタンの押下をシミュレートするには、UiDevice.pressHome() を呼び出します。 メソッドを呼び出します。

UI Automator API

UI Automator API を使用すると、知識がなくても堅牢なテストを作成できる (ターゲットにしているアプリの実装の詳細)次を使用: 以下の API を使用して、複数のアプリにわたって UI コンポーネントをキャプチャして操作します。

  • UiObject2: デバイスに表示される UI 要素を表します。
  • BySelector: UI 要素のマッチング条件を指定します。
  • By: 簡潔な方法で BySelector を作成します。
  • Configurator: UI Automator テストを実行するための主要なパラメータを設定できます。
で確認できます。

たとえば、次のコードは、実行するテスト スクリプトを デバイスで Gmail アプリを開く

Kotlin


device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.pressHome()

val gmail: UiObject2 = device.findObject(By.text("Gmail"))
// Perform a click and wait until the app is opened.
val opened: Boolean = gmail.clickAndWait(Until.newWindow(), 3000)
assertThat(opened).isTrue()

Java


device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.pressHome();

UiObject2 gmail = device.findObject(By.text("Gmail"));
// Perform a click and wait until the app is opened.
Boolean opened = gmail.clickAndWait(Until.newWindow(), 3000);
assertTrue(opened);

UI Automator をセットアップする

UI Automator で UI テストを作成する前に、必ずテストを構成してください ソースコードの場所とプロジェクトの依存関係(プロジェクトの設定 AndroidX Test のテストをご覧ください。

Android アプリ モジュールの build.gradle ファイルで、依存関係を設定する必要があります。 UI Automator ライブラリを参照できます。

Kotlin

dependencies {
  ...
  androidTestImplementation('androidx.test.uiautomator:uiautomator:2.3.0-alpha03')
}

Groovy

dependencies {
  ...
  androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0-alpha03'
}

UI Automator のテストを最適化するには、まずターゲット アプリの UI コンポーネントを作成し、それらがアクセス可能であることを確認します。これらの最適化のヒントは 次の 2 つのセクションで説明します。

デバイス上の UI を検査する

テストを設計する前に、 できます。UI Automator テストでこれらのコンポーネントにアクセスできるようにするには、 これらのコンポーネントに、表示されるテキストラベル android:contentDescription の値、またはその両方)。

uiautomatorviewer ツールは、検査に役立つ便利なビジュアル インターフェースを備えています。 表示される UI コンポーネントのプロパティを表示する アプリが起動します。この情報により UI Automator を使用してきめ細かいテストを行えます。たとえば UI セレクタを作成し 一致します

uiautomatorviewer ツールを起動するには:

  1. 物理デバイスでターゲット アプリを起動します。
  2. デバイスを開発マシンに接続します。
  3. ターミナル ウィンドウを開いて、<android-sdk>/tools/ ディレクトリに移動します。
  4. 次のコマンドを使用してツールを実行します。
 $ uiautomatorviewer

アプリの UI プロパティを表示するには:

  1. uiautomatorviewer インターフェースで、[Device Screenshot] ボタンをクリックします。
  2. 左側のパネルのスナップショットにカーソルを合わせると、UI コンポーネントが表示されます。 uiautomatorviewer ツールによって識別される API。プロパティは、 下回っています レイアウト階層が表示されます。
  3. 必要に応じて、[Toggle NAF Nodes] ボタンをクリックして UI コンポーネントを表示 UI Automator がアクセスできない リソースを定義できます限られた情報しか これらのコンポーネントで使用できます。

Android が提供する UI コンポーネントの一般的なタイプについては、ユーザー インターフェースをご覧ください。

アクティビティのユーザー補助機能を確認する

UI Automator テスト フレームワークは、実装したアプリでより優れたパフォーマンスを発揮します。 Android のユーザー補助機能。View タイプの UI 要素を使用する場合、または のサブクラス(SDK の View のサブクラス)を使用すると、ユーザー補助を実装する必要が これらのクラスでは、すでにそのように行われています。

一部のアプリでは、より豊かなユーザー エクスペリエンスを提供するためにカスタム UI 要素を使用しています。 そのような要素は、自動的にはユーザー補助サポートを提供しません。アプリが SDK 以外の View のサブクラスのインスタンスが含まれるため、 これらの要素にユーザー補助機能を追加するには、 手順は次のとおりです。

  1. ExploreByTouchHelper を拡張する具象クラスを作成します。
  2. 新しいクラスのインスタンスを特定のカスタム UI 要素に関連付ける setAccessibilityDelegate() の呼び出し

カスタムビューにユーザー補助機能を追加する方法について詳しくは、 アクセシビリティ対応のカスタムビューの作成をご覧ください。詳細情報 Android でのユーザー補助に関する一般的なベスト プラクティスについては、アプリの利便性を高める アクセス可能

UI Automator テストクラスを作成する

UI Automator テストクラスは JUnit 4 テストと同じ方法で記述する必要があります クラスです。JUnit 4 テストクラスの作成と JUnit 4 の使用方法の詳細 アサーションとアノテーションについては、インストルメンテーション 単体テストクラスを作成するをご覧ください。

テストの先頭に @RunWith(AndroidJUnit4.class) アノテーションを追加する クラス定義をご覧ください。AndroidJUnitRunner クラスも指定する必要があります。 AndroidX Test で提供されています。このステップは 詳しくは、デバイスまたはエミュレータで UI Automator テストを実行するをご覧ください。

UI Automator テストクラスに、次のプログラミング モデルを実装します。

  1. 以下を呼び出して、テストするデバイスにアクセスするための UiDevice オブジェクトを取得します。 getInstance() メソッドを実行し、Instrumentation オブジェクトとして 渡します。
  2. 画面に表示される UI コンポーネントにアクセスするための UiObject2 オブジェクトを取得します。 (たとえば、フォアグラウンドの現在のビューなど)に findObject() メソッド。
  3. その UI コンポーネントで実行する特定のユーザー操作をシミュレートします。手順は次のとおりです。 UiObject2 メソッドを呼び出す。たとえば、 スクロールするには scrollUntil()、テキスト フィールドを編集するには setText() を使用します。 ステップ 2 と 3 で API を呼び出すことができます。 複雑なユーザー操作をテストするために、必要に応じて繰り返しテストし、 複数の UI コンポーネントや一連の ユーザーアクションで構成されます
  4. このようなユーザーのその後の UI が、想定される状態や動作を反映していることを確認する 行います。

上記の手順については、以降のセクションで詳しく説明します。

UI コンポーネントにアクセスする

UiDevice オブジェクトは、 確認します。テストでは、UiDevice メソッドを呼び出して 現在の向きやディスプレイ サイズなど、さまざまなプロパティの状態。 テストでは、UiDevice オブジェクトを使用して、デバイスレベルのアクションを実行できます。 たとえば、デバイスを特定の回転状態にする、D-pad ハードウェアを押す、 [ホーム] ボタンや [メニュー] ボタンを押すなどの操作を行えます。

デバイスのホーム画面からテストを始めることをおすすめします。最低料金 ホーム画面(またはデバイスで選択したその他の開始位置) UI Automator API に用意されたメソッドを呼び出して、 特定の UI 要素でトレーニングできます

次のコード スニペットは、テストで UiDevice を実行し、ホームボタンの押下をシミュレートします。

Kotlin


import org.junit.Before
import androidx.test.runner.AndroidJUnit4
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
...

private const val BASIC_SAMPLE_PACKAGE = "com.example.android.testing.uiautomator.BasicSample"
private const val LAUNCH_TIMEOUT = 5000L
private const val STRING_TO_BE_TYPED = "UiAutomator"

@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 18)
class ChangeTextBehaviorTest2 {

private lateinit var device: UiDevice

@Before
fun startMainActivityFromHomeScreen() {
  // Initialize UiDevice instance
  device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

  // Start from the home screen
  device.pressHome()

  // Wait for launcher
  val launcherPackage: String = device.launcherPackageName
  assertThat(launcherPackage, notNullValue())
  device.wait(
    Until.hasObject(By.pkg(launcherPackage).depth(0)),
    LAUNCH_TIMEOUT
  )

  // Launch the app
  val context = ApplicationProvider.getApplicationContext<Context>()
  val intent = context.packageManager.getLaunchIntentForPackage(
  BASIC_SAMPLE_PACKAGE).apply {
    // Clear out any previous instances
    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
  }
  context.startActivity(intent)

  // Wait for the app to appear
  device.wait(
    Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
    LAUNCH_TIMEOUT
    )
  }
}

Java


import org.junit.Before;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Until;
...

@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class ChangeTextBehaviorTest {

  private static final String BASIC_SAMPLE_PACKAGE
  = "com.example.android.testing.uiautomator.BasicSample";
  private static final int LAUNCH_TIMEOUT = 5000;
  private static final String STRING_TO_BE_TYPED = "UiAutomator";
  private UiDevice device;

  @Before
  public void startMainActivityFromHomeScreen() {
    // Initialize UiDevice instance
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

    // Start from the home screen
    device.pressHome();

    // Wait for launcher
    final String launcherPackage = device.getLauncherPackageName();
    assertThat(launcherPackage, notNullValue());
    device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
    LAUNCH_TIMEOUT);

    // Launch the app
    Context context = ApplicationProvider.getApplicationContext();
    final Intent intent = context.getPackageManager()
    .getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
    // Clear out any previous instances
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    context.startActivity(intent);

    // Wait for the app to appear
    device.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
    LAUNCH_TIMEOUT);
    }
}

この例では、@SdkSuppress(minSdkVersion = 18) ステートメントにより、 Android 4.3(API レベル 18)以上を搭載したデバイスでのみテストが実行されるようにすること。 UI Automator のフレームワークで必要な いくつかのリソースが用意されています

findObject() メソッドを使用して、データを表す UiObject2 を取得します。 ビューを返します。UiObject2 は再利用できます。 作成したインスタンスを必要に応じて追加してみます。 なお、UI Automator テスト フレームワークは、現在のディスプレイで テストが UiObject2 インスタンスを使用して UI をクリックするたびに一致します。 プロパティのクエリを実行できます

次のスニペットは、テストで UiObject2 を構築する方法を示しています。 アプリの [Cancel] ボタンと [OK] ボタンを表すインスタンス。

Kotlin


val okButton: UiObject2 = device.findObject(
    By.text("OK").clazz("android.widget.Button")
)

// Simulate a user-click on the OK button, if found.
if (okButton != null) {
    okButton.click()
}

Java


UiObject2 okButton = device.findObject(
    By.text("OK").clazz("android.widget.Button")
);

// Simulate a user-click on the OK button, if found.
if (okButton != null) {
    okButton.click();
}

セレクタを指定する

アプリの特定の UI コンポーネントにアクセスするには、 By クラスを使用して BySelector インスタンスを作成します。BySelector は、表示された UI の特定の要素に対するクエリを表します。

一致する要素が複数見つかった場合は、 レイアウト階層がターゲット UiObject2 として返されます。Deployment の構成を BySelector は、複数のプロパティを連結してプロパティを絞り込むことができます。 できます。一致する UI 要素が見つからない場合は、null が返されます。

hasChild() または hasDescendant() メソッドを使用して、メッセージをネストできます。 複数の BySelector インスタンスを使用できます。たとえば、次のコードサンプルは、 テストで、最初の ListView を見つけるための検索を指定する方法 text プロパティを持つ子 UI 要素があります。

Kotlin


val listView: UiObject2 = device.findObject(
    By.clazz("android.widget.ListView")
        .hasChild(
            By.text("Apps")
        )
)

Java


UiObject2 listView = device.findObject(
    By.clazz("android.widget.ListView")
        .hasChild(
            By.text("Apps")
        )
);

セレクタの条件としてオブジェクトの状態を指定する方法が適切な場合もあります。対象 たとえば、オンにしたすべての要素のリストを選択して、 チェックボックスをオフにし、引数を true に設定して checked() メソッドを呼び出します。

アクションを実行する

テストで UiObject2 オブジェクトを取得したら、 UI コンポーネントでユーザー インタラクションを実行する UiObject2 クラス そのオブジェクトで表されるデータです。次のようなアクションの指定が可能です。

  • click() : UI 要素の表示境界の中心をクリックします。
  • drag() : このオブジェクトを任意の座標にドラッグします。
  • setText() : 編集可能なフィールドに 表示されます。逆に、clear() メソッドは既存のテキストを消去します。 入力します。
  • swipe() : 指定した方向にスワイプします。
  • scrollUntil(): 指定された方向へスクロール操作を行います。 Condition または EventCondition の条件が満たされるまで。

UI Automator テスト フレームワークでは、Intent を送信するか、 Context を取得し、シェルコマンドを使用せずにアクティビティを オブジェクトを getContext() で設定します。

次のスニペットは、テストで Intent を使用して テスト対象アプリです。この方法は、テストのみに関心がある場合に有用です。 ランチャーについては関係ありません

Kotlin


fun setUp() {
...

  // Launch a simple calculator app
  val context = getInstrumentation().context
  val intent = context.packageManager.getLaunchIntentForPackage(CALC_PACKAGE).apply {
    addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
  }
  // Clear out any previous instances
  context.startActivity(intent)
  device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT)
}

Java


public void setUp() {
...

  // Launch a simple calculator app
  Context context = getInstrumentation().getContext();
  Intent intent = context.getPackageManager()
  .getLaunchIntentForPackage(CALC_PACKAGE);
  intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

  // Clear out any previous instances
  context.startActivity(intent);
  device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
}

結果を検証する

InstrumentationTestCaseTestCase を拡張するため、 アプリの UI コンポーネントが返すことをテストする標準の JUnit Assert メソッド 示されます。

次のスニペットは、画面内の複数のボタンをテストで見つける方法を示しています。 クリックして順番にクリックして、正しい結果が 表示されます。

Kotlin


private const val CALC_PACKAGE = "com.myexample.calc"

fun testTwoPlusThreeEqualsFive() {
  // Enter an equation: 2 + 3 = ?
  device.findObject(By.res(CALC_PACKAGE, "two")).click()
  device.findObject(By.res(CALC_PACKAGE, "plus")).click()
  device.findObject(By.res(CALC_PACKAGE, "three")).click()
  device.findObject(By.res(CALC_PACKAGE, "equals")).click()

  // Verify the result = 5
  val result: UiObject2 = device.findObject(By.res(CALC_PACKAGE, "result"))
  assertEquals("5", result.text)
}

Java


private static final String CALC_PACKAGE = "com.myexample.calc";

public void testTwoPlusThreeEqualsFive() {
  // Enter an equation: 2 + 3 = ?
  device.findObject(By.res(CALC_PACKAGE, "two")).click();
  device.findObject(By.res(CALC_PACKAGE, "plus")).click();
  device.findObject(By.res(CALC_PACKAGE, "three")).click();
  device.findObject(By.res(CALC_PACKAGE, "equals")).click();

  // Verify the result = 5
  UiObject2 result = device.findObject(By.res(CALC_PACKAGE, "result"));
  assertEquals("5", result.getText());
}

デバイスまたはエミュレータで UI Automator テストを実行する

UI Automator テストは、Android Studio または 使用します。AndroidJUnitRunner をデフォルトとして指定してください。 インストルメンテーションランナーを使用します

その他の例

システム UI を操作する

UI Automator は、システムを含め、画面上のあらゆる要素を操作できます。 追加することをおすすめします。次のコード スニペットをご覧ください。

Kotlin


// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.executeShellCommand("am start -a android.settings.SETTINGS")

Java


// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.executeShellCommand("am start -a android.settings.SETTINGS");

Kotlin


// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openNotification()

Java


// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openNotification();

Kotlin


// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openQuickSettings()

Java


// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openQuickSettings();

Kotlin


// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"))
print(clock.getText())

Java


// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"));
print(clock.getText());

遷移を待つ

サイレント モードをオフにする
図 1. UI Automator が、特定のデバイスでサイレント モードを テストします。

画面の遷移には時間がかかる場合があり、その継続時間の予測は信頼できません。 オペレーションの実行後は UI Automator が待機する必要があります。UI Automator これには複数の方法があります。

次のコード スニペットは、UI Automator を使用して [Do Not] をオフにする方法を示しています。 システム設定でサイレント モードを使用する(performActionAndWait() メソッドを使用) 遷移を待機します。

Kotlin


@Test
@SdkSuppress(minSdkVersion = 21)
@Throws(Exception::class)
fun turnOffDoNotDisturb() {
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    device.performActionAndWait({
        try {
            device.executeShellCommand("am start -a android.settings.SETTINGS")
        } catch (e: IOException) {
            throw RuntimeException(e)
        }
    }, Until.newWindow(), 1000)
    // Check system settings has been opened.
    Assert.assertTrue(device.hasObject(By.pkg("com.android.settings")))

    // Scroll the settings to the top and find Notifications button
    var scrollableObj: UiObject2 = device.findObject(By.scrollable(true))
    scrollableObj.scrollUntil(Direction.UP, Until.scrollFinished(Direction.UP))
    val notificationsButton = scrollableObj.findObject(By.text("Notifications"))

    // Click the Notifications button and wait until a new window is opened.
    device.performActionAndWait({ notificationsButton.click() }, Until.newWindow(), 1000)
    scrollableObj = device.findObject(By.scrollable(true))
    // Scroll down until it finds a Do Not Disturb button.
    val doNotDisturb = scrollableObj.scrollUntil(
        Direction.DOWN,
        Until.findObject(By.textContains("Do Not Disturb"))
    )
    device.performActionAndWait({ doNotDisturb.click() }, Until.newWindow(), 1000)
    // Turn off the Do Not Disturb.
    val turnOnDoNotDisturb = device.findObject(By.text("Turn on now"))
    turnOnDoNotDisturb?.click()
    Assert.assertTrue(device.wait(Until.hasObject(By.text("Turn off now")), 1000))
}

Java


@Test
@SdkSuppress(minSdkVersion = 21)
public void turnOffDoNotDisturb() throws Exception{
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    device.performActionAndWait(() -> {
        try {
            device.executeShellCommand("am start -a android.settings.SETTINGS");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }, Until.newWindow(), 1000);
    // Check system settings has been opened.
    assertTrue(device.hasObject(By.pkg("com.android.settings")));

    // Scroll the settings to the top and find Notifications button
    UiObject2 scrollableObj = device.findObject(By.scrollable(true));
    scrollableObj.scrollUntil(Direction.UP, Until.scrollFinished(Direction.UP));
    UiObject2 notificationsButton = scrollableObj.findObject(By.text("Notifications"));

    // Click the Notifications button and wait until a new window is opened.
    device.performActionAndWait(() -> notificationsButton.click(), Until.newWindow(), 1000);
    scrollableObj = device.findObject(By.scrollable(true));
    // Scroll down until it finds a Do Not Disturb button.
    UiObject2 doNotDisturb = scrollableObj.scrollUntil(Direction.DOWN,
            Until.findObject(By.textContains("Do Not Disturb")));
    device.performActionAndWait(()-> doNotDisturb.click(), Until.newWindow(), 1000);
    // Turn off the Do Not Disturb.
    UiObject2 turnOnDoNotDisturb = device.findObject(By.text("Turn on now"));
    if(turnOnDoNotDisturb != null) {
        turnOnDoNotDisturb.click();
    }
    assertTrue(device.wait(Until.hasObject(By.text("Turn off now")), 1000));
}

参考情報

Android テストで UI Automator を使用する方法について詳しくは、 ご覧ください

リファレンス ドキュメント:

サンプル

  • BasicSample: UI Automator の基本的なサンプルです。