כתיבת בדיקות אוטומטיות באמצעות UI Automator (הנחיות לגרסה הקודמת)

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

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

התכונות העיקריות של מסגרת הבדיקה 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.

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

Kotlin

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

גרוב

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

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

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

אובייקט UiDevice הוא הדרך העיקרית לגשת למצב המכשיר ולשנות אותו. בבדיקות, אפשר להפעיל שיטות של UiDevice כדי לבדוק את המצב של מאפיינים שונים, כמו האוריינטציה הנוכחית או גודל המסך. אפשר להשתמש באובייקט UiDevice בבדיקה כדי לבצע פעולות ברמת המכשיר, כמו כניסה בכוח לסיבוב ספציפי, לחיצה על לחצני חומרה של D-pad ולחיצה על הלחצנים Home ו-Menu.

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

בקטע הקוד הבא מוצג איך הבדיקה יכולה לקבל מופע של 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.