UI অটোমেটর দিয়ে স্বয়ংক্রিয় পরীক্ষা লিখুন

UI Automator টেস্টিং ফ্রেমওয়ার্কটি ইউজার অ্যাপ এবং সিস্টেম অ্যাপের সাথে ইন্টারঅ্যাক্ট করে এমন UI টেস্ট তৈরি করার জন্য একগুচ্ছ API প্রদান করে।

আধুনিক UI অটোমেটর টেস্টিং-এর পরিচিতি

UI Automator 2.4 একটি সুবিন্যস্ত, কোটলিন-বান্ধব ডোমেইন স্পেসিফিক ল্যাঙ্গুয়েজ (DSL) নিয়ে এসেছে যা অ্যান্ড্রয়েডের জন্য UI টেস্ট লেখা সহজ করে। এই নতুন API সারফেসটি প্রেডিকেট-ভিত্তিক এলিমেন্ট ফাইন্ডিং এবং অ্যাপ স্টেটের উপর সুস্পষ্ট নিয়ন্ত্রণের উপর আলোকপাত করে। আরও রক্ষণাবেক্ষণযোগ্য এবং নির্ভরযোগ্য অটোমেটেড টেস্ট তৈরি করতে এটি ব্যবহার করুন।

UI Automator আপনাকে অ্যাপের প্রসেসের বাইরে থেকে অ্যাপটি পরীক্ষা করার সুযোগ দেয়। এর মাধ্যমে আপনি মিনিফিকেশন প্রয়োগ করা রিলিজ সংস্করণগুলো পরীক্ষা করতে পারেন। ম্যাক্রোবেঞ্চমার্ক টেস্ট লেখার ক্ষেত্রেও UI Automator সাহায্য করে।

আধুনিক পদ্ধতির প্রধান বৈশিষ্ট্যগুলো হলো:

  • আরও পরিচ্ছন্ন এবং অর্থপূর্ণ টেস্ট কোডের জন্য একটি বিশেষ uiAutomator টেস্ট স্কোপ।
  • স্পষ্ট প্রেডিকেটসহ UI এলিমেন্ট খুঁজে বের করার জন্য onElement , onElements , এবং onElementOrNull মতো মেথড।
  • শর্তসাপেক্ষ উপাদানগুলির জন্য অন্তর্নির্মিত অপেক্ষার প্রক্রিয়া onElement*(timeoutMs: Long = 10000)
  • অ্যাপের সুস্পষ্ট অবস্থা ব্যবস্থাপনা, যেমন waitForStable এবং waitForAppToBeVisible
  • একাধিক উইন্ডো পরীক্ষার ক্ষেত্রে অ্যাক্সেসিবিলিটি উইন্ডো নোডগুলির সাথে সরাসরি মিথস্ক্রিয়া।
  • ভিজ্যুয়াল টেস্টিং এবং ডিবাগিংয়ের জন্য অন্তর্নির্মিত স্ক্রিনশট নেওয়ার সুবিধা এবং একটি ResultsReporter রয়েছে।

আপনার প্রজেক্ট সেট আপ করুন

আধুনিক UI Automator API ব্যবহার শুরু করতে, আপনার প্রোজেক্টের build.gradle.kts ফাইলটি আপডেট করে সর্বশেষ ডিপেন্ডেন্সিটি অন্তর্ভুক্ত করুন:

কোটলিন

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

গ্রুভি

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

মূল এপিআই ধারণা

নিম্নলিখিত বিভাগগুলিতে আধুনিক UI অটোমেটর 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 উপাদান খুঁজুন

UI এলিমেন্ট সনাক্ত করতে প্রেডিকেট সহ UI অটোমেটর API ব্যবহার করুন। এই প্রেডিকেটগুলো আপনাকে টেক্সট, নির্বাচিত বা ফোকাসড অবস্থা এবং বিষয়বস্তুর বিবরণের মতো প্রোপার্টিগুলোর জন্য শর্ত নির্ধারণ করতে দেয়।

  • onElement { predicate } : একটি ডিফল্ট টাইমআউটের মধ্যে প্রেডিকেটের সাথে মেলে এমন প্রথম UI এলিমেন্টটি রিটার্ন করে। যদি ফাংশনটি কোনো মিলযুক্ত এলিমেন্ট খুঁজে না পায়, তবে এটি একটি এক্সেপশন থ্রো করে।

    // 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 } : অন্তত একটি UI এলিমেন্ট প্রদত্ত প্রেডিকেটের সাথে মিলে যাওয়া পর্যন্ত অপেক্ষা করে, তারপর মিলে যাওয়া সমস্ত UI এলিমেন্টের একটি তালিকা ফেরত দেয়।

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

UI উপাদানগুলির সাথে ইন্টারঅ্যাক্ট করুন

ক্লিক অনুকরণ করে অথবা সম্পাদনাযোগ্য ফিল্ডে টেক্সট সেট করে UI এলিমেন্টগুলোর সাথে ইন্টারঅ্যাক্ট করুন।

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

অ্যাপের অবস্থা এবং পর্যবেক্ষকদের পরিচালনা করুন

আপনার অ্যাপের জীবনচক্র পরিচালনা করুন এবং পরীক্ষার সময় প্রদর্শিত হতে পারে এমন অপ্রত্যাশিত UI উপাদানগুলি সামলান।

অ্যাপ জীবনচক্র ব্যবস্থাপনা

এপিআইগুলো পরীক্ষাধীন অ্যাপের অবস্থা নিয়ন্ত্রণ করার উপায় প্রদান করে:

// 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")

অপ্রত্যাশিত UI পরিচালনা করুন

watchFor API আপনাকে অপ্রত্যাশিত UI এলিমেন্ট, যেমন পারমিশন ডায়ালগ, যা আপনার টেস্ট ফ্লো চলাকালীন প্রদর্শিত হতে পারে, সেগুলোর জন্য হ্যান্ডলার নির্ধারণ করতে দেয়। এটি অভ্যন্তরীণ ওয়াচার মেকানিজম ব্যবহার করে, কিন্তু আরও বেশি নমনীয়তা প্রদান করে।

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 বেশ কিছু API প্রদান করে।

waitForAppToBeVisible("com.example.targetapp") ফাংশনটি একটি কাস্টমাইজযোগ্য টাইমআউটের মধ্যে প্রদত্ত প্যাকেজ নামের একটি UI এলিমেন্ট স্ক্রিনে প্রদর্শিত হওয়ার জন্য অপেক্ষা করে।

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

অ্যাপের UI ব্যবহার করার আগে, সেটি স্থিতিশীল কিনা তা যাচাই করতে 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 অটোমেটর ব্যবহার করুন

Jetpack Macrobenchmark-এর সাহায্যে পারফরম্যান্স টেস্টিং এবং বেসলাইন প্রোফাইল তৈরির জন্য UI Automator ব্যবহার করুন, কারণ এটি আপনার অ্যাপের সাথে ইন্টারঅ্যাক্ট করার এবং একজন শেষ ব্যবহারকারীর দৃষ্টিকোণ থেকে পারফরম্যান্স পরিমাপ করার একটি নির্ভরযোগ্য উপায় প্রদান করে।

ম্যাক্রোবেঞ্চমার্ক UI পরিচালনা করতে এবং ইন্টারঅ্যাকশন পরিমাপ করতে UI অটোমেটর API ব্যবহার করে। উদাহরণস্বরূপ, স্টার্টআপ বেঞ্চমার্কে, UI কন্টেন্ট কখন সম্পূর্ণরূপে লোড হয় তা শনাক্ত করতে আপনি onElement ব্যবহার করতে পারেন, যা আপনাকে টাইম টু ফুল ডিসপ্লে (TTFD) পরিমাপ করতে সক্ষম করে। জ্যাঙ্ক বেঞ্চমার্কে, ফ্রেম টাইমিং পরিমাপ করার জন্য তালিকা স্ক্রল করতে বা অ্যানিমেশন চালাতে UI অটোমেটর API ব্যবহার করা হয়। পরিমাপ শুরু হওয়ার আগে অ্যাপটিকে সঠিক অবস্থায় আনার জন্য startActivity() বা startIntent() এর মতো ফাংশনগুলো সহায়ক।

বেসলাইন প্রোফাইল তৈরি করার সময়, কোন ক্লাস এবং মেথডগুলোর প্রি-কম্পাইলেশন প্রয়োজন তা রেকর্ড করার জন্য আপনি আপনার অ্যাপের গুরুত্বপূর্ণ ইউজার জার্নি (CUJ) স্বয়ংক্রিয় করেন। এই অটোমেশন স্ক্রিপ্টগুলো লেখার জন্য UI Automator একটি আদর্শ টুল। আধুনিক DSL-এর প্রেডিকেট-ভিত্তিক এলিমেন্ট ফাইন্ডিং এবং বিল্ট-ইন ওয়েট মেকানিজম ( onElement ) অন্যান্য পদ্ধতির তুলনায় আরও শক্তিশালী এবং ডিটারমিনিস্টিক টেস্ট এক্সিকিউশন নিশ্চিত করে। এই স্থিতিশীলতা ফ্ল্যাকিনেস কমায় এবং নিশ্চিত করে যে তৈরি করা বেসলাইন প্রোফাইলটি আপনার সবচেয়ে গুরুত্বপূর্ণ ইউজার ফ্লো চলাকালীন এক্সিকিউট হওয়া কোড পাথগুলোকে সঠিকভাবে প্রতিফলিত করে।

উন্নত বৈশিষ্ট্য

আরও জটিল পরীক্ষার ক্ষেত্রে নিম্নলিখিত বৈশিষ্ট্যগুলি উপযোগী।

একাধিক উইন্ডোর সাথে ইন্টারঅ্যাক্ট করুন

UI Automator API-গুলো আপনাকে UI এলিমেন্টগুলোর সাথে সরাসরি ইন্টারঅ্যাক্ট করতে এবং সেগুলোকে পরীক্ষা করতে দেয়। একাধিক উইন্ডো জড়িত এমন পরিস্থিতিতে, যেমন পিকচার-ইন-পিকচার (PiP) মোড বা স্প্লিট-স্ক্রিন লেআউটের ক্ষেত্রে এটি বিশেষভাবে উপযোগী।

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

স্ক্রিনশট এবং চাক্ষুষ দাবি

আপনার টেস্টের মধ্যেই সরাসরি পুরো স্ক্রিন, নির্দিষ্ট উইন্ডো বা স্বতন্ত্র UI এলিমেন্টের স্ক্রিনশট নিন। এটি ভিজ্যুয়াল রিগ্রেশন টেস্টিং এবং ডিবাগিংয়ের জন্য সহায়ক।

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

বিটম্যাপের জন্য saveToFile এক্সটেনশন ফাংশনটি ধারণ করা ছবিকে একটি নির্দিষ্ট পাথে সংরক্ষণ করা সহজ করে তোলে।

ডিবাগিংয়ের জন্য ResultsReporter ব্যবহার করুন

ResultsReporter আপনাকে অ্যান্ড্রয়েড স্টুডিওতে আপনার পরীক্ষার ফলাফলের সাথে স্ক্রিনশটের মতো টেস্ট আর্টিফ্যাক্টগুলো সরাসরি যুক্ত করতে সাহায্য করে, যার ফলে পরিদর্শন এবং ডিবাগিং আরও সহজ হয়।

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 Autotor সংস্করণগুলি থেকে মাইগ্রেট করুন

আপনার যদি পুরোনো এপিআই সারফেস ব্যবহার করে লেখা বিদ্যমান UI Automator টেস্ট থাকে, তবে আধুনিক পদ্ধতিতে স্থানান্তরিত হওয়ার জন্য নিম্নলিখিত সারণিটি রেফারেন্স হিসেবে ব্যবহার করুন:

কর্মের ধরণ পুরানো UI অটোমেটর পদ্ধতি নতুন UI অটোমেটর পদ্ধতি
প্রবেশ বিন্দু UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) টেস্ট লজিককে uiAutomator { ... } স্কোপের মধ্যে রাখুন।
UI উপাদান খুঁজুন device.findObject(By.res("com.example.app:id/my_button")) onElement { viewIdResourceName == "my\_button" }
UI উপাদান খুঁজুন device.findObject(By.text("Click Me")) onElement { textAsString() == "Click Me" }
নিষ্ক্রিয় UI এর জন্য অপেক্ষা করুন device.waitForIdle() onElement এর বিল্ট-ইন টাইমআউট মেকানিজম ব্যবহার করা শ্রেয়; অন্যথায়, activeWindow().waitForStable() ব্যবহার করুন।
চাইল্ড এলিমেন্ট খুঁজুন ম্যানুয়ালি নেস্টেড findObject কল onElement().onElement() চেইনিং
অনুমতি ডায়ালগগুলি পরিচালনা করুন UiAutomator.registerWatcher() watchFor(PermissionDialog)