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

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

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

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

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

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

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

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

לדוגמה, כדי לדמות לחיצה על לחצן דף הבית, קוראים לפונקציה UiDevice.pressHome() .

ממשקי API Automator API

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

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

לדוגמה, הקוד הבא מראה איך לכתוב סקריפט לבדיקה פותחת אפליקציית 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);

הגדרת אוטומציה של ממשק המשתמש

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

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

Kotlin

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

Groovy

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

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

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

לפני תכנון הבדיקה, יש לבדוק את רכיבי ממשק המשתמש הגלויים במכשיר. כדי להבטיח שהבדיקות של ממשק המשתמש האוטומטי יוכלו לגשת לרכיבים האלה, לבדוק שלרכיבים האלה יש תוויות טקסט גלויות, android:contentDescription, או את שניהם.

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

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

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

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

  1. בממשק uiautomatorviewer, לוחצים על הלחצן צילום מסך של מכשיר.
  2. כדי לראות את רכיבי ממשק המשתמש, מעבירים את העכבר מעל תמונת המצב בחלונית הימנית זוהה על ידי הכלי uiautomatorviewer. הנכסים מפורטים נמוכה יותר את החלונית השמאלית ואת היררכיית הפריסה בחלונית השמאלית העליונה.
  3. אפשר גם ללחוץ על הלחצן השבתה או הפעלה של צומתי NAF כדי לראות את רכיבי ממשק המשתמש שלא נגישים ל-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 טענות נכונות (assertions) והערות, ראו יצירת כיתה של בדיקת יחידה אינסטרומנטלית.

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

תטמיעו את מודל התכנות הבא בשיעור הבדיקה של אוטומציה של ממשק המשתמש:

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

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

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

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

מומלץ להתחיל את הבדיקה ממסך הבית של המכשיר. מאת במסך הבית (או מיקום התחלה אחר שבחרתם במכשיר), אפשר לקרוא ל-methods שמסופקות על ידי 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) ומעלה, כנדרש על ידי ה-framework של ה-UI Automator.

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

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

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

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

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

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

ה-InstrumentationTestCase מרחיב את TestCase, כך שאפשר להשתמש שיטות רגילות של 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());
}

הרצת בדיקות של אוטומציה של ממשק המשתמש במכשיר או באמולטור

אפשר להריץ בדיקות של האוטומציה של ממשק המשתמש מ-Android Studio או דרך בשורת הפקודה. חשוב לציין את AndroidJUnitRunner כברירת המחדל הפעלת אינסטרומנטציה בפרויקט.

דוגמאות נוספות

אינטראקציה עם ממשק המשתמש של המערכת

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

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 כדי להשבית את 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));
}

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

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

מסמכי עזר:

דוגמיות

  • BasicSample: דוגמת אוטומציה של ממשק משתמש בסיסי.