यूज़र इंटरफ़ेस (यूआई) ऑटोमेशन की मदद से, अपने-आप होने वाले टेस्ट में बदलाव करने की सुविधा

UI Automator टेस्टिंग फ़्रेमवर्क, यूज़र इंटरफ़ेस (यूआई) टेस्ट बनाने के लिए एपीआई का एक सेट उपलब्ध कराता है. ये एपीआई, उपयोगकर्ता के ऐप्लिकेशन और सिस्टम ऐप्लिकेशन के साथ इंटरैक्ट करते हैं.

मॉडर्न यूज़र इंटरफ़ेस ऑटोमेटर टेस्टिंग के बारे में जानकारी

UI Automator 2.4 में, Kotlin के साथ काम करने वाली Domain Specific Language (DSL) को पेश किया गया है. इससे Android के लिए यूज़र इंटरफ़ेस (यूआई) टेस्ट लिखना आसान हो जाता है. एपीआई का यह नया वर्शन, प्रेडिकेट के आधार पर एलिमेंट ढूंढने और ऐप्लिकेशन की स्थितियों को साफ़ तौर पर कंट्रोल करने पर फ़ोकस करता है. इसका इस्तेमाल, रखरखाव में आसान और भरोसेमंद ऑटोमेटेड टेस्ट बनाने के लिए करें.

UI Automator की मदद से, ऐप्लिकेशन की प्रोसेस के बाहर से ऐप्लिकेशन की जांच की जा सकती है. इससे, आपको रिलीज़ किए जाने वाले वर्शन की जांच करने में मदद मिलती है. इसमें कोड छोटा करने की सुविधा लागू होती है. मैक्रोबेंचमार्क टेस्ट लिखते समय भी UI Automator का इस्तेमाल किया जा सकता है.

आधुनिक तरीके की मुख्य सुविधाएं:

  • साफ़ और ज़्यादा जानकारी देने वाले टेस्ट कोड के लिए, uiAutomator टेस्ट स्कोप.
  • यूज़र इंटरफ़ेस (यूआई) एलिमेंट ढूंढने के लिए, onElement, onElements, और onElementOrNull जैसे तरीकों का इस्तेमाल किया जा सकता है.
  • कंडिशनल एलिमेंट onElement*(timeoutMs: Long = 10000) के लिए, इंतज़ार करने का पहले से मौजूद तरीका
  • ऐप्लिकेशन की स्थिति को साफ़ तौर पर मैनेज करने की सुविधा, जैसे कि waitForStable और waitForAppToBeVisible.
  • मल्टी-विंडो टेस्टिंग के अलग-अलग चरणों के लिए, ऐक्सेसिबिलिटी विंडो नोड के साथ सीधे तौर पर इंटरैक्ट करने की सुविधा.
  • स्क्रीनशॉट लेने की बिल्ट-इन सुविधाएं और विज़ुअल टेस्टिंग और डीबग करने के लिए ResultsReporter.

अपना प्रोजेक्ट सेट अप करना

मॉडर्न UI Automator API का इस्तेमाल शुरू करने के लिए, अपने प्रोजेक्ट की build.gradle.kts फ़ाइल को अपडेट करें, ताकि इसमें नई डिपेंडेंसी शामिल हो:

Kotlin

dependencies {
  ...
  androidTestImplementation("androidx.test.uiautomator:uiautomator:2.4.0-alpha05")
}

Groovy

dependencies {
  ...
  androidTestImplementation "androidx.test.uiautomator:uiautomator:2.4.0-alpha05"
}

Core API के मुख्य सिद्धांत

यहां दिए गए सेक्शन में, मॉडर्न यूज़र इंटरफ़ेस (यूआई) ऑटोमेटर एपीआई के मुख्य सिद्धांतों के बारे में बताया गया है.

uiAutomator टेस्ट का दायरा

uiAutomator { ... } ब्लॉक में, सभी नए UI Automator API ऐक्सेस करें. यह फ़ंक्शन एक UiAutomatorTestScope बनाता है. यह आपकी टेस्ट कार्रवाइयों के लिए, छोटा और टाइप-सेफ़ एनवायरमेंट उपलब्ध कराता है.

uiAutomator {
  // All your UI Automator actions go here
  startApp("com.example.targetapp")
  onElement { textAsString() == "Hello, World!" }.click()
}

यूज़र इंटरफ़ेस (यूआई) एलिमेंट ढूंढना

यूआई एलिमेंट ढूंढने के लिए, प्रेडिकेट के साथ UI Automator API का इस्तेमाल करें. इन प्रेडिकेट की मदद से, टेक्स्ट, चुनी गई या फ़ोकस की गई स्थिति, और कॉन्टेंट के ब्यौरे जैसी प्रॉपर्टी के लिए शर्तें तय की जा सकती हैं.

  • onElement { predicate }: यह फ़ंक्शन, डिफ़ॉल्ट टाइम आउट में, प्रेडिकेट से मेल खाने वाले पहले यूज़र इंटरफ़ेस (यूआई) एलिमेंट को दिखाता है. अगर फ़ंक्शन को मैच करने वाला कोई एलिमेंट नहीं मिलता है, तो यह एक अपवाद दिखाता है.

    // Find a button with the text "Submit" and click it
    onElement { textAsString() == "Submit" }.click()
    
    // Find a UI element by its resource ID
    onElement { viewIdResourceName == "my_button_id" }.click()
    
    // Allow a permission request
    watchFor(PermissionDialog) {
      clickAllow()
    }
    
  • onElementOrNull { predicate }: यह onElement जैसा ही है, लेकिन टाइम आउट होने पर कोई भी मैचिंग एलिमेंट न मिलने पर null दिखाता है. इससे कोई अपवाद नहीं मिलता. इस तरीके का इस्तेमाल, वैकल्पिक एलिमेंट के लिए करें.

    val optionalButton = onElementOrNull { textAsString() == "Skip" }
    optionalButton?.click() // Click only if the button exists
    
  • onElements { predicate }: यह तब तक इंतज़ार करता है, जब तक कम से कम एक यूज़र इंटरफ़ेस (यूआई) एलिमेंट, दिए गए प्रेडिकेट से मैच नहीं हो जाता. इसके बाद, यह मैच होने वाले सभी यूज़र इंटरफ़ेस (यूआई) एलिमेंट की सूची दिखाता है.

    // Get all items in a list Ui element
    val listItems = onElements { className == "android.widget.TextView" && isClickable }
    listItems.forEach { it.click() }
    

onElement कॉल का इस्तेमाल करने के लिए, यहां कुछ सुझाव दिए गए हैं:

  • नेस्ट किए गए एलिमेंट के लिए onElement कॉल को चेन करना: पैरंट-चाइल्ड के क्रम के हिसाब से, onElement कॉल को चेन करके, दूसरे एलिमेंट में मौजूद एलिमेंट ढूंढे जा सकते हैं.

    // Find a parent Ui element with ID "first", then its child with ID "second",
    // then its grandchild with ID "third", and click it.
    onElement { viewIdResourceName == "first" }
      .onElement { viewIdResourceName == "second" }
      .onElement { viewIdResourceName == "third" }
      .click()
    
  • onElement* फ़ंक्शन के लिए टाइम आउट तय करें. इसके लिए, मिलीसेकंड में वैल्यू पास करें.

    // Find a Ui element with a zero timeout (instant check)
    onElement(0) { viewIdResourceName == "something" }.click()
    
    // Find a Ui element with a custom timeout of 10 seconds
    onElement(10_000) { textAsString() == "Long loading text" }.click()
    

यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ इंटरैक्ट करना

क्लिक का सिम्युलेशन करके या टेक्स्ट को बदले जा सकने वाले फ़ील्ड में सेट करके, यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ इंटरैक्ट करें.

// Click a Ui element
onElement { textAsString() == "Tap Me" }.click()

// Set text in an editable field
onElement { className == "android.widget.EditText" }.setText("My input text")

// Perform a long click
onElement { contentDescription == "Context Menu" }.longClick()

ऐप्लिकेशन की स्थितियों और वॉचर को मैनेज करना

अपने ऐप्लिकेशन की लाइफ़साइकल को मैनेज करें. साथ ही, जांच के दौरान दिखने वाले अनचाहे यूज़र इंटरफ़ेस (यूआई) एलिमेंट को हैंडल करें.

ऐप्लिकेशन के लाइफ़साइकल का मैनेजमेंट

एपीआई, जांच किए जा रहे ऐप्लिकेशन की स्थिति को कंट्रोल करने के तरीके उपलब्ध कराते हैं:

// Start a specific app by package name. Used for benchmarking and other
// self-instrumenting tests.
startApp("com.example.targetapp")

// Start a specific activity within the target app
startActivity(SomeActivity::class.java)

// Start an intent
startIntent(myIntent)

// Clear the app's data (resets it to a fresh state)
clearAppData("com.example.targetapp")

अनचाहे यूज़र इंटरफ़ेस (यूआई) को मैनेज करना

watchFor एपीआई की मदद से, यूज़र इंटरफ़ेस (यूआई) के उन अनचाहे एलिमेंट के लिए हैंडलर तय किए जा सकते हैं जो टेस्ट फ़्लो के दौरान दिख सकते हैं. जैसे, अनुमति के लिए डायलॉग बॉक्स. यह इंटरनल वॉचर मैकेनिज़्म का इस्तेमाल करता है, लेकिन इसमें ज़्यादा सुविधाएं मिलती हैं.

import androidx.test.uiautomator.PermissionDialog

@Test
fun myTestWithPermissionHandling() = uiAutomator {
  startActivity(MainActivity::class.java)

  // Register a watcher to click "Allow" if a permission dialog appears
  watchFor(PermissionDialog) { clickAllow() }

  // Your test steps that might trigger a permission dialog
  onElement { textAsString() == "Request Permissions" }.click()

  // Example: You can register a different watcher later if needed
  clearAppData("com.example.targetapp")

  // Now deny permissions
  startApp("com.example.targetapp")
  watchFor(PermissionDialog) { clickDeny() }
  onElement { textAsString() == "Request Permissions" }.click()
}

PermissionDialog, ScopedWatcher<T> का एक उदाहरण है. इसमें T, watchFor में ब्लॉक को स्कोप के तौर पर पास किया गया ऑब्जेक्ट है. इस पैटर्न के आधार पर, कस्टम वॉचर बनाए जा सकते हैं.

ऐप्लिकेशन के दिखने और उसके क्रैश या फ़्रीज़ हुए बिना काम करने तक इंतज़ार करें

कभी-कभी, टेस्ट को एलिमेंट के दिखने या स्थिर होने का इंतज़ार करना पड़ता है. UI Automator, इस काम के लिए कई एपीआई उपलब्ध कराता है.

waitForAppToBeVisible("com.example.targetapp"), दिए गए पैकेज के नाम वाले यूज़र इंटरफ़ेस (यूआई) एलिमेंट के स्क्रीन पर दिखने का इंतज़ार करता है. इसके लिए, टाइम आउट की अवधि को अपनी पसंद के मुताबिक सेट किया जा सकता है.

// Wait for the app to be visible after launching it
startApp("com.example.targetapp")
waitForAppToBeVisible("com.example.targetapp")

waitForStable() API का इस्तेमाल करके, यह पुष्टि करें कि ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) के साथ इंटरैक्ट करने से पहले, उसे स्टेबल माना जाता है.

// Wait for the entire active window to become stable
activeWindow().waitForStable()

// Wait for a specific Ui element to become stable (e.g., after a loading animation)
onElement { viewIdResourceName == "my_loading_indicator" }.waitForStable()

बेहतर सुविधाएं

यहां दी गई सुविधाएं, टेस्टिंग के ज़्यादा मुश्किल उदाहरणों के लिए काम की हैं.

एक साथ कई विंडो के साथ इंटरैक्ट करना

UI Automator API की मदद से, यूज़र इंटरफ़ेस (यूआई) एलिमेंट के साथ सीधे तौर पर इंटरैक्ट किया जा सकता है और उनकी जांच की जा सकती है. यह खास तौर पर उन स्थितियों में काम आता है जिनमें एक से ज़्यादा विंडो शामिल होती हैं. जैसे, पिक्चर में पिक्चर (पीआईपी) मोड या स्प्लिट-स्क्रीन लेआउट.

// Find the first window that is in Picture-in-Picture mode
val pipWindow = windows()
  .first { it.isInPictureInPictureMode == true }

// Now you can interact with elements within that specific window
pipWindow.onElement { textAsString() == "Play" }.click()

स्क्रीनशॉट और विज़ुअल पुष्टि

अपनी जाँचों में सीधे तौर पर पूरी स्क्रीन, चुनिंदा विंडो या यूज़र इंटरफ़ेस (यूआई) के अलग-अलग एलिमेंट के स्क्रीनशॉट कैप्चर करें. यह विज़ुअल रिग्रेशन टेस्टिंग और डीबग करने के लिए मददगार है.

uiautomator {
  // Take a screenshot of the entire active window
  val fullScreenBitmap: Bitmap = activeWindow().takeScreenshot()
  fullScreenBitmap.saveToFile(File("/sdcard/Download/full_screen.png"))

  // Take a screenshot of a specific UI element (e.g., a button)
  val buttonBitmap: Bitmap = onElement { viewIdResourceName == "my_button" }.takeScreenshot()
  buttonBitmap.saveToFile(File("/sdcard/Download/my_button_screenshot.png"))

  // Example: Take a screenshot of a PiP window
  val pipWindowScreenshot = windows()
    .first { it.isInPictureInPictureMode == true }
    .takeScreenshot()
  pipWindowScreenshot.saveToFile(File("/sdcard/Download/pip_screenshot.png"))
}

Bitmap के लिए saveToFile एक्सटेंशन फ़ंक्शन, कैप्चर की गई इमेज को तय किए गए पाथ पर सेव करने की प्रोसेस को आसान बनाता है.

डीबग करने के लिए, ResultsReporter का इस्तेमाल करना

ResultsReporter की मदद से, टेस्ट आर्टफ़ैक्ट (जैसे, स्क्रीनशॉट) को सीधे तौर पर Android Studio में टेस्ट के नतीजों से जोड़ा जा सकता है. इससे जांच और डीबग करना आसान हो जाता है.

uiAutomator {
  startApp("com.example.targetapp")

  val reporter = ResultsReporter("MyTestArtifacts") // Name for this set of results
  val file = reporter.addNewFile(
    filename = "my_screenshot",
    title = "Accessible button image" // Title that appears in Android Studio test results
  )

  // Take a screenshot of an element and save it using the reporter
  onElement { textAsString() == "Accessible button" }
    .takeScreenshot()
    .saveToFile(file)

  // Report the artifacts to instrumentation, making them visible in Android Studio
  reporter.reportToInstrumentation()
}

UI Automator के पुराने वर्शन से माइग्रेट करना

अगर आपके पास पुराने एपीआई की मदद से लिखी गई मौजूदा यूज़र इंटरफ़ेस (यूआई) ऑटोमेटर टेस्ट हैं, तो आधुनिक तरीके पर माइग्रेट करने के लिए, इस टेबल का इस्तेमाल करें:

कार्रवाई का टाइप UI Automator का पुराना तरीका UI Automator का नया तरीका
एंट्री पॉइंट UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) टेस्ट लॉजिक को uiAutomator { ... } स्कोप में रैप करें.
यूज़र इंटरफ़ेस (यूआई) एलिमेंट ढूंढना device.findObject(By.res("com.example.app:id/my_button")) onElement { viewIdResourceName == "my\_button" }
यूज़र इंटरफ़ेस (यूआई) एलिमेंट ढूंढना device.findObject(By.text("Click Me")) onElement { textAsString() == "Click Me" }
यूज़र इंटरफ़ेस (यूआई) के निष्क्रिय होने का इंतज़ार करें device.waitForIdle() onElement में मौजूद टाइम आउट की सुविधा को प्राथमिकता दें; अगर ऐसा नहीं होता है, तो activeWindow().waitForStable()
चाइल्ड एलिमेंट ढूंढना मैन्युअल तरीके से नेस्ट किए गए findObject कॉल onElement().onElement() चेनिंग
अनुमति वाले डायलॉग बॉक्स को मैनेज करना UiAutomator.registerWatcher() watchFor(PermissionDialog)