كتابة الاختبارات المبرمجة باستخدام واجهة المستخدم التلقائية

UI Automator هو إطار عمل لاختبار واجهة المستخدم، وهو مناسب لاختبار واجهة المستخدم الوظيفية في جميع التطبيقات على مستوى النظام والتطبيقات المثبّتة. تتيح لك واجهات برمجة التطبيقات في UI Automator التفاعل مع العناصر المرئية على الجهاز، بغض النظر عن Activity التي يتم التركيز عليها، ما يتيح لك تنفيذ عمليات مثل فتح قائمة "الإعدادات" أو مشغّل التطبيقات في جهاز اختبار. يمكن أن يبحث اختبارك عن مكوّن واجهة مستخدم باستخدام وصفيّات ملائمة، مثل النص المعروض في هذا المكوّن أو وصفه المحتوى.

إطار عمل اختبار UI Automator هو واجهة برمجة تطبيقات مستندة إلى الأدوات، ويعمل مع أداة تشغيل الاختبار AndroidJUnitRunner. وهو مناسب تمامًا لكتابة اختبارات آلية بأسلوب مربّعات غير شفافة، حيث لا يعتمد رمز الاختبار على تفاصيل التنفيذ الداخلية للتطبيق المستهدَف.

تشمل الميزات الرئيسية لإطار عمل اختبار UI Automator ما يلي:

  • واجهة برمجة تطبيقات لاسترداد معلومات الحالة وتنفيذ العمليات على الجهاز المستهدَف لمزيد من المعلومات، يُرجى الاطّلاع على الوصول إلى حالة الجهاز.
  • واجهات برمجة التطبيقات التي تتيح اختبار واجهة المستخدم في جميع التطبيقات لمزيد من المعلومات، يُرجى الاطّلاع على واجهات برمجة تطبيقات UI Automator.

الوصول إلى حالة الجهاز

يقدّم إطار عمل اختبار UI Automator فئة UiDevice للوصول إلى العمليات وتنفيذها على الجهاز الذي يعمل عليه التطبيق المستهدَف. يمكنك استدعاء طرقها للوصول إلى خصائص الجهاز، مثل الاتجاه الحالي أو حجم الشاشة. تتيح لك فئة UiDevice أيضًا تنفيذ الإجراءات التالية:

  1. تغيير وضع دوران الجهاز
  2. اضغط على مفاتيح الجهاز، مثل "رفع مستوى الصوت".
  3. اضغط على زر الرجوع أو زر الشاشة الرئيسية أو زر القائمة.
  4. افتح مركز الإشعارات.
  5. التقط لقطة شاشة للنافذة الحالية.

على سبيل المثال، لمحاكاة الضغط على زر الشاشة الرئيسية، يمكنك استدعاء الطريقة UiDevice.pressHome().

واجهات برمجة تطبيقات UI Automator

تتيح لك واجهات برمجة التطبيقات UI Automator كتابة اختبارات فعّالة بدون الحاجة إلى معرفة تفاصيل تنفيذ التطبيق الذي تستهدفه. يمكنك استخدام واجهات برمجة التطبيقات هذه لالتقاط عناصر واجهة المستخدم ومعالجتها في تطبيقات متعددة:

  • 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، احرص على ضبط ملف اختبار الموقع الجغرافي للرمز المصدر وتبعيات المشروع، كما هو موضّح في مقالة إعداد ملف project لاختبار 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. يمكنك اختياريًا النقر على الزر تبديل عقد 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، اطّلِع على مقالة إنشاء فئة اختبار وحدة أدوات.

أضِف التعليق التوضيحي @RunWith(AndroidJUnit4.class) في بداية تعريف ملف اختبار الفئة. عليك أيضًا تحديد فئة AndroidJUnitRunner، المقدَّمة في AndroidX Test، لتكون أداة تشغيل الاختبار التلقائية. يتم وصف هذه الخطوة بالتفصيل في مقالة تشغيل اختبارات UI Automator على جهاز أو محاكي.

نفِّذ نموذج البرمجة التالي في فئة اختبار UI Automator:

  1. احصل على عنصر UiDevice للوصول إلى الجهاز الذي تريد اختباره، وذلك من خلال استدعاء طريقة getInstance()‎ وتمرير عنصر Instrumentation إليها كهي briquette
  2. احصل على عنصر UiObject2 للوصول إلى مكوّن واجهة مستخدم معروض على الجهاز (على سبيل المثال، العرض الحالي في المقدّمة)، وذلك من خلال استدعاء الأسلوب findObject()‎.
  3. يمكنك محاكاة تفاعل مستخدم معيّن لتنفيذه على مكوّن واجهة المستخدم هذا، وذلك من خلال استدعاء طريقة UiObject2. على سبيل المثال، يمكنك استدعاء scrollUntil() للانتقال إلى أسفل الصفحة وsetText() لتعديل حقل نصي. يمكنك طلب واجهات برمجة التطبيقات في الخطوتَين 2 و3 بشكل متكرّر حسب الحاجة لاختبار تفاعلات المستخدِمين الأكثر تعقيدًا التي تتضمّن مكوّنات متعددة لواجهة المستخدِم أو تسلسلات من إجراءات المستخدِمين.
  4. تأكَّد من أنّ واجهة المستخدم تعكس الحالة أو السلوك المتوقّعَين بعد تنفيذ تفاعلات المستخدِم هذه.

وتتضمّن الأقسام أدناه مزيدًا من التفاصيل حول هذه الخطوات.

الوصول إلى مكونات واجهة المستخدم

عنصر UiDevice هو الطريقة الأساسية للوصول إلى حالة الجهاز والتحكم فيها. في اختباراتك، يمكنك استدعاء طرق UiDevice للتحقّق من حالة السمات المختلفة، مثل الاتجاه الحالي أو حجم الشاشة. يمكن أن يستخدم اختبارك العنصر UiDevice لتنفيذ إجراءات على مستوى الجهاز، مثل إجبار الجهاز على التدوير بزاوية معيّنة، والضغط على أزرار لوحة التوجيه المتعرجة، والضغط على زرَّي Home وMenu.

من الممارسات الجيدة بدء الاختبار من الشاشة الرئيسية للجهاز. من الشاشة الرئيسية (أو أي موقع بداية آخر اخترته في الجهاز)، يمكنك استدعاء الطرق التي يوفّرها واجهة برمجة التطبيقات UI Automator لاختيار عناصر واجهة مستخدم معيّنة والتفاعل معها.

يوضّح المقتطف التالي من الرمز البرمجي كيفية الحصول على مثيل من UiDevice في الاختبار ومحاكاة الضغط على زر Home (الصفحة الرئيسية):

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 (المستوى 18 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، على النحو المطلوب من إطار عمل UI Automator.

استخدِم طريقة findObject() لاسترداد UiObject2 الذي يمثّل عرضًا يتطابق مع معايير أداة اختيار معيّنة. يمكنك إعادة استخدام UiObject2 المثيلَين اللذَين أنشأتهما في أجزاء أخرى من اختبار تطبيقك، حسب الحاجة. يُرجى العِلم أنّ إطار عمل اختبار UI Automator يبحث في الشاشة الحالية عن مطابقة في كل مرة يستخدم فيها الاختبار مثيل 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();
}

تحديد أداة اختيار

إذا كنت تريد الوصول إلى مكوّن واجهة مستخدم معيّن في أحد التطبيقات، استخدِم فئة By لإنشاء مثيل BySelector. يمثّل BySelector طلب بحث عن عناصر معيّنة في واجهة المستخدم المعروضة.

إذا تم العثور على أكثر من عنصر مطابق واحد، يتم عرض أول عنصر مطابق في التسلسل الهرمي لتنسيق العنصر على أنّه الهدف UiObject2. عند إنشاء BySelector، يمكنك ربط مواقع متعددة معًا لتحسين بحثك. إذا لم يتم العثور على عنصر واجهة مستخدم مطابق، يتم عرض null.

يمكنك استخدام الطريقة hasChild() أو hasDescendant() لتضمين نُسخ متعددة من BySelector. على سبيل المثال، يوضّح مثال الرمز البرمجي التالي كيف يمكن لاختبارك تحديد عملية بحث للعثور على أول ListView يتضمّن عنصر واجهة مستخدم فرعيًا يتضمّن السمة text.

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 أو بدء نشاط بدون استخدام أوامر shell، وذلك من خلال الحصول على عنصر سياق من خلال 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، لذا يمكنك استخدام methodsAssert العادية في 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());

الانتظار إلى أن تكتمل عمليات النقل

إيقاف وضع &quot;عدم الإزعاج&quot;
الشكل 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