שימוש ב-API מדור קודם של UI Automator

‫UI Automator הוא framework לבדיקת ממשק משתמש שמתאים לבדיקות פונקציונליות של ממשק משתמש באפליקציות שונות, במערכת ובאפליקציות מותקנות. ממשקי ה-API של UI Automator מאפשרים אינטראקציה עם רכיבים גלויים במכשיר, בלי קשר ל-Activity שנמצא בפוקוס, כך שאפשר לבצע פעולות כמו פתיחת תפריט ההגדרות או מגירת האפליקציות במכשיר בדיקה. הבדיקה יכולה לחפש רכיב בממשק המשתמש באמצעות תיאורים נוחים כמו הטקסט שמוצג ברכיב או תיאור התוכן שלו.

‫UI Automator הוא API מבוסס-מכשור שפועל עם AndroidJUnitRunner test runner. הוא מתאים במיוחד לכתיבת בדיקות אוטומטיות בסגנון קופסה אטומה, שבהן קוד הבדיקה לא מסתמך על פרטי הטמעה פנימיים של אפליקציית היעד.

התכונות העיקריות של מסגרת הבדיקה UI Automator כוללות את האפשרויות הבאות:

  • ממשק API לאחזור מידע על מצב המכשיר ולביצוע פעולות במכשיר היעד. מידע נוסף זמין במאמר בנושא גישה למצב המכשיר.
  • ממשקי API שתומכים בבדיקות ממשק משתמש בין אפליקציות. מידע נוסף זמין במאמר ממשקי API של UI Automator.

גישה למצב המכשיר

ה-Framework לבדיקות UI Automator מספק מחלקה UiDevice לגישה למכשיר שבו פועלת אפליקציית היעד ולביצוע פעולות בו. אפשר להתקשר לשיטות שלו כדי לגשת למאפייני המכשיר, כמו האוריינטציה הנוכחית או גודל המסך. בנוסף, המחלקה UiDevice מאפשרת לבצע את הפעולות הבאות:

  1. שינוי הסיבוב של המכשיר.
  2. לוחצים על מקשי חומרה, כמו 'הגברת עוצמת הקול'.
  3. לוחצים על הלחצנים 'חזרה', 'בית' או 'תפריט'.
  4. פותחים את לוח ההתראות.
  5. מצלמים את המסך של החלון הנוכחי.

לדוגמה, כדי לדמות לחיצה על הלחצן הראשי, קוראים לשיטה UiDevice.pressHome().

UI Automator APIs

ממשקי ה-API של UI Automator מאפשרים לכתוב בדיקות חזקות בלי שתצטרכו לדעת פרטים על ההטמעה של האפליקציה שאתם מכוונים אליה. אפשר להשתמש בממשקי ה-API האלה כדי לצלם ולערוך רכיבי ממשק משתמש בכמה אפליקציות:

  • UiObject2: מייצג רכיב בממשק המשתמש שמוצג במכשיר.
  • BySelector: מציין קריטריונים להתאמה של רכיבי ממשק משתמש.
  • 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 באמצעות UI Automator, צריך להגדיר את המיקום של קוד המקור של הבדיקה ואת יחסי התלות של הפרויקט, כמו שמתואר במאמר הגדרת פרויקט ל-AndroidX Test.

בקובץ build.gradle של מודול אפליקציית Android, צריך להגדיר הפניה לתלות בספריית UI Automator:

Kotlin

dependencies { ... androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0") }

Groovy

dependencies { ... androidTestImplementation "androidx.test.uiautomator:uiautomator:2.3.0" }

כדי לבצע אופטימיזציה של הבדיקות באמצעות UI Automator, קודם צריך לבדוק את רכיבי ממשק המשתמש של אפליקציית היעד ולוודא שיש אליהם גישה. הטיפים האלה לאופטימיזציה מפורטים בשני הקטעים הבאים.

בדיקת ממשק המשתמש במכשיר

לפני שתתכננו את הבדיקה, כדאי לבדוק את רכיבי ממשק המשתמש שגלויים במכשיר. כדי לוודא שבדיקות UI Automator יכולות לגשת לרכיבים האלה, צריך לבדוק אם לרכיבים האלה יש תוויות טקסט גלויות, ערכי android:contentDescription או שניהם.

uiautomatorviewer הכלי מספק ממשק חזותי נוח לבדיקת ההיררכיה של הפריסה ולצפייה במאפיינים של רכיבים בממשק המשתמש שגלויים בחזית המכשיר. המידע הזה מאפשר לכם ליצור בדיקות מפורטות יותר באמצעות UI Automator. לדוגמה, אפשר ליצור בורר של ממשק משתמש שתואם למאפיין ספציפי שגלוי למשתמש.

כדי להפעיל את הכלי uiautomatorviewer:

  1. מפעילים את אפליקציית היעד במכשיר פיזי.
  2. מחברים את המכשיר למכונת הפיתוח.
  3. פותחים חלון טרמינל ועוברים לספרייה <android-sdk>/tools/.
  4. מריצים את הכלי באמצעות הפקודה הבאה:
 $ uiautomatorviewer

כדי לראות את מאפייני ממשק המשתמש של האפליקציה:

  1. בממשק uiautomatorviewer, לוחצים על הלחצן צילום מסך של המכשיר.
  2. מעבירים את העכבר מעל התמונה בחלונית הימנית כדי לראות את רכיבי ממשק המשתמש שזוהו על ידי הכלי uiautomatorviewer. הנכסים מופיעים בחלונית השמאלית התחתונה, והיררכיית הפריסה מופיעה בחלונית השמאלית העליונה.
  3. אפשר גם ללחוץ על הלחצן Toggle NAF Nodes כדי לראות רכיבי ממשק משתמש שלא נגישים ל-UI Automator. יכול להיות שיהיה מידע מוגבל בלבד לגבי הרכיבים האלה.

מידע על הסוגים הנפוצים של רכיבי ממשק משתמש ש-Android מספקת זמין במאמר ממשק משתמש.

מוודאים שאפשר לגשת לפעילות

מסגרת הבדיקה UI Automator פועלת טוב יותר באפליקציות שבהן הוטמעו תכונות הנגישות של Android. כשמשתמשים באלמנטים של ממשק משתמש מהסוג View, או במחלקה משנית של View מה-SDK, לא צריך להטמיע תמיכה בנגישות, כי המחלקות האלה כבר עושות את זה בשבילכם.

עם זאת, יש אפליקציות שמשתמשות ברכיבי ממשק משתמש מותאמים אישית כדי לספק חוויית משתמש עשירה יותר. רכיבים כאלה לא יספקו תמיכה אוטומטית בנגישות. אם האפליקציה שלכם מכילה מקרים של מחלקת משנה של View שלא מגיעה מ-SDK, חשוב להוסיף רכיבי נגישות לאלמנטים האלה. כדי לעשות זאת, צריך לבצע את השלבים הבאים:

  1. יוצרים מחלקה קונקרטית שמרחיבה את ExploreByTouchHelper.
  2. כדי לשייך מופע של המחלקה החדשה לרכיב ספציפי בממשק המשתמש בהתאמה אישית, צריך לקרוא ל-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. כדי לגשת לרכיב בממשק המשתמש שמוצג במכשיר (לדוגמה, התצוגה הנוכחית בחזית), צריך לקרוא לשיטה findObject() כדי לקבל אובייקט UiObject2.
  3. מדמים אינטראקציה ספציפית של משתמש עם רכיב ממשק המשתמש באמצעות קריאה לשיטה UiObject2. לדוגמה, קוראים ל-scrollUntil() כדי לגלול, ול-setText() כדי לערוך שדה טקסט. אפשר להפעיל את ממשקי ה-API בשלבים 2 ו-3 שוב ושוב לפי הצורך כדי לבדוק אינטראקציות מורכבות יותר של משתמשים שכוללות רכיבים מרובים של ממשק המשתמש או רצפים של פעולות משתמש.
  4. בודקים שממשק המשתמש משקף את המצב או את אופן הפעולה הצפויים, אחרי ביצוע האינטראקציות האלה של המשתמש.

השלבים האלה מוסברים בפירוט בקטעים הבאים.

גישה לרכיבי ממשק המשתמש

אובייקט UiDevice הוא הדרך העיקרית לגשת למצב המכשיר ולשנות אותו. בבדיקות, אפשר להפעיל שיטות של UiDevice כדי לבדוק את המצב של מאפיינים שונים, כמו האוריינטציה הנוכחית או גודל המסך. אפשר להשתמש באובייקט UiDevice בבדיקה כדי לבצע פעולות ברמת המכשיר, כמו כניסה בכוח לסיבוב ספציפי, לחיצה על לחצני החומרה של מקשי החיצים ולחיצה על הלחצנים 'דף הבית' ו'תפריט'.

מומלץ להתחיל את הבדיקה ממסך הבית של המכשיר. ממסך הבית (או ממיקום התחלתי אחר שבחרתם במכשיר), אתם יכולים להפעיל את השיטות שמופיעות ב-API של UI Automator כדי לבחור רכיבי ממשק משתמש ספציפיים ולבצע איתם אינטראקציה.

קטע הקוד הבא מראה איך הבדיקה יכולה לקבל מופע של 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 test framework מחפש התאמה בתצוגה הנוכחית בכל פעם שהבדיקה משתמשת במופע UiObject2 כדי ללחוץ על רכיב בממשק המשתמש או כדי לשלוח שאילתה לגבי מאפיין.

בקטע הקוד הבא אפשר לראות איך הבדיקה יכולה ליצור מופעים של UiObject2 לחצן ביטול ולחצן אישור באפליקציה.

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();
}

ציון בורר

אם רוצים לגשת לרכיב ספציפי בממשק המשתמש באפליקציה, צריך להשתמש במחלקה By כדי ליצור מופע BySelector. ‫BySelector מייצג שאילתה של רכיבים ספציפיים בממשק המשתמש שמוצג.

אם נמצא יותר מרכיב אחד שתואם, מוחזר הרכיב התואם הראשון בהיררכיית הפריסה כיעד UiObject2. כשיוצרים BySelector, אפשר לשרשר כמה מאפיינים כדי לדייק את החיפוש. אם לא נמצא רכיב תואם בממשק המשתמש, מוחזר null.

אפשר להשתמש ב-method‏ hasChild() או ב-method‏ hasDescendant() כדי להטמיע כמה מופעים של BySelector. לדוגמה, בדוגמת הקוד הבאה מוצג אופן ההגדרה של חיפוש בבדיקה כדי למצוא את ListView הראשון שיש לו רכיב 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")
        )
);

מומלץ לציין את מצב האובייקט בקריטריונים של הבורר. לדוגמה, אם רוצים לבחור רשימה של כל הרכיבים המסומנים כדי לנקות אותם, קוראים לשיטה checked() עם הארגומנט שמוגדר כ-true.

ביצוע פעולות

אחרי שמקבלים אובייקט UiObject2 של הבדיקה, אפשר לקרוא למתודות במחלקה UiObject2 כדי לבצע אינטראקציות של משתמשים ברכיב ממשק המשתמש שמיוצג על ידי האובייקט הזה. אפשר לציין פעולות כמו:

  • click() : לחיצה על מרכז הגבולות הגלויים של רכיב בממשק המשתמש.
  • drag() : גוררים את האובייקט הזה לקואורדינטות שרירותיות.
  • setText() : מגדיר את הטקסט בשדה שניתן לערוך, אחרי שמנקים את התוכן של השדה. לעומת זאת, השיטה clear() מוחקת את הטקסט הקיים בשדה שניתן לעריכה.
  • swipe() : מבצע את פעולת ההחלקה לכיוון שצוין.
  • scrollUntil(): מבצע את פעולת הגלילה לכיוון שצוין עד שמתקיים התנאי Condition או EventCondition.

מסגרת הבדיקה UI Automator מאפשרת לשלוח Intent או להפעיל Activity בלי להשתמש בפקודות של מעטפת, על ידי קבלת אובייקט 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);
}

אימות התוצאות

InstrumentationTestCase הוא הרחבה של TestCase, כך שאפשר להשתמש ב-methods הרגילים של Assert ב-JUnit כדי לבדוק שרכיבי ממשק המשתמש באפליקציה מחזירים את התוצאות הצפויות.

קטע הקוד הבא מראה איך הבדיקה יכולה לאתר כמה לחצנים באפליקציית מחשבון, ללחוץ עליהם לפי הסדר ואז לוודא שהתוצאה הנכונה מוצגת.

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 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 כדי להשבית את המצב 'נא לא להפריע' בהגדרות המערכת באמצעות השיטה 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));
}

מקורות מידע נוספים

מידע נוסף על השימוש ב-UI Automator בבדיקות של Android זמין במקורות המידע הבאים.

מאמרי עזרה:

דוגמיות

  • BasicSample: דוגמה בסיסית ל-UI Automator.