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

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()
}

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

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

  • 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 { id == "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 { id == "first" }
      .onElement { id == "second" }
      .onElement { id == "third" }
      .click()
    
  • onElement* फ़ंक्शन के लिए टाइम आउट तय करें. इसके लिए, मिलीसेकंड में वैल्यू पास करें.

    // Find a Ui element with a zero timeout (instant check)
    onElement(0) { id == "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 { id == "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 { id == "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"))
}

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