כתיבת בדיקות אוטומטיות באמצעות UI Automator

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

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

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

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

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

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

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

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

ממשקי API של UI Automator

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

  • UiObject2: מייצג אלמנט בממשק המשתמש שגלוי במכשיר.
  • BySelector: מציינים קריטריונים להתאמה של רכיבי ממשק המשתמש.
  • By: יצירת BySelector באופן תמציתי.
  • Configurator: מאפשר להגדיר פרמטרים מרכזיים להרצת בדיקות של UI Automator.

לדוגמה, הקוד הבא מראה איך אפשר לכתוב סקריפט בדיקה שפותח את אפליקציית Gmail במכשיר:

KotlinJava
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()
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, חשוב להגדיר את המיקום של קוד המקור של הבדיקה ואת יחסי התלות בפרויקט, כפי שמתואר במאמר הגדרת פרויקט ל-AndroidX Test.

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

KotlinGroovy
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. מעבירים את העכבר מעל קובץ snapshot בחלונית הימנית כדי לראות את רכיבי ממשק המשתמש שזוהו באמצעות הכלי 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 ועל שימוש בהצהרות נכוֹנוּת (assertions) ובהערות (annotations) של JUnit 4 זמין במאמר יצירת כיתה של בדיקת יחידה עם כלי למדידת ביצועים.

מוסיפים את ההערה @RunWith(AndroidJUnit4.class) בתחילת ההגדרה של הכיתה לבדיקה. צריך גם לציין את הכיתה AndroidJUnitRunner, שסופקת ב-AndroidX Test, בתור הכלי שמריץ את הבדיקות כברירת מחדל. שלב זה מתואר בפירוט רב יותר בקטע הרצת בדיקות של UI Automator במכשיר או במהדמה.

מטמיעים את מודל התכנות הבא בכיתה של בדיקת UI Automator:

  1. כדי לקבל גישה למכשיר שרוצים לבדוק, צריך לקבל אובייקט UiDevice על ידי קריאה ל-method‏ getInstance()‎ והעברת אובייקט Instrumentation כארגומנטים.
  2. כדי לקבל אובייקט UiObject2 ולגשת לרכיב בממשק המשתמש שמוצג במכשיר (לדוגמה, התצוגה הנוכחית בחזית), צריך לבצע קריאה לשיטה findObject()‎.
  3. כדי לדמות אינטראקציה ספציפית של משתמש ברכיב ממשק המשתמש הזה, קוראים לשיטה UiObject2. לדוגמה, קוראים ל-scrollUntil()‎ כדי לגלול, ול-setText()‎ כדי לערוך שדה טקסט. אפשר לקרוא לממשקי ה-API בשלבים 2 ו-3 שוב ושוב לפי הצורך כדי לבדוק אינטראקציות מורכבות יותר של משתמשים שכוללות כמה רכיבים של ממשק המשתמש או רצפים של פעולות של משתמשים.
  4. בודקים שממשק המשתמש משקף את המצב או את ההתנהגות הצפויים, אחרי ביצוע האינטראקציות האלה עם המשתמשים.

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

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

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

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

קטע הקוד הבא מראה איך הבדיקה יכולה לקבל מופע של UiDevice ולבצע סימולציה של לחיצה על לחצן הבית:

KotlinJava
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
    )
  }
}
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.

משתמשים ב-method‏ findObject() כדי לאחזר UiObject2 שמייצג תצוגה שתואמת לקריטריונים של בורר נתון. תוכלו לעשות שימוש חוזר במכונות UiObject2 שיצרתם בחלקים אחרים של בדיקת האפליקציה, לפי הצורך. חשוב לזכור ש-UI Automator Framework מחפש התאמה במסך הנוכחי בכל פעם שבבדיקה נעשה שימוש במכונה של UiObject2 כדי ללחוץ על רכיב בממשק המשתמש או לשלוח שאילתה לנכס.

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

KotlinJava
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()
}
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 מייצג שאילתה לרכיבים ספציפיים בממשק המשתמש המוצג.

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

אפשר להשתמש ב-method hasChild() או ב-method hasDescendant() כדי להטמיע מספר מכונות BySelector. לדוגמה, בדוגמת הקוד הבאה מוסבר איך אפשר לציין בחיפוש של הבדיקה את ListView הראשון שיש לו רכיב UI צאצא עם מאפיין הטקסט.

KotlinJava
val listView: UiObject2 = device.findObject(
    By.clazz("android.widget.ListView")
        .hasChild(
            By.text("Apps")
        )
)
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 בבדיקה כדי להפעיל את האפליקציה שנבדקת. הגישה הזו שימושית אם אתם רוצים לבדוק רק את אפליקציית המחשבון ולא את מרכז האפליקציות.

KotlinJava
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)
}
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, כך שאפשר להשתמש בשיטות Assert הסטנדרטיות של JUnit כדי לבדוק שמרכיבי ממשק המשתמש באפליקציה מחזירים את התוצאות הצפויות.

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

KotlinJava
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)
}
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 יכול לקיים אינטראקציה עם כל מה שמופיע במסך, כולל רכיבי מערכת מחוץ לאפליקציה, כפי שמוצג בקטעי הקוד הבאים:

KotlinJava
// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.executeShellCommand("am start -a android.settings.SETTINGS")
// Opens the System Settings.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.executeShellCommand("am start -a android.settings.SETTINGS");
KotlinJava
// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openNotification()
// Opens the notification shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openNotification();
KotlinJava
// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
device.openQuickSettings()
// Opens the Quick Settings shade.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
device.openQuickSettings();
KotlinJava
// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"))
print(clock.getText())
// Get the system clock.
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
UiObject2 clock = device.findObject(By.res("com.android.systemui:id/clock"));
print(clock.getText());

המתנה למעברים

השבתת המצב &#39;נא לא להפריע&#39;
איור 1. UI Automator משבית את מצב 'נא לא להפריע' במכשיר בדיקה.

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

קטע הקוד הבא מראה איך להשתמש ב-UI Automator כדי להשבית את המצב 'נא לא להפריע' בהגדרות המערכת באמצעות השיטה performActionAndWait() שמחכה למעברים:

KotlinJava
@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))
}
@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.