Espresso সম্পর্কিত প্রাথমিক বিষয়

Espresso API ব্যবহার করে কীভাবে সাধারণ অটোমেটেড টেস্টিং টাস্ক সম্পূর্ণ করতে হয় তা এই ডকুমেন্টে ব্যাখ্যা করা হয়েছে।

Espresso API টেস্ট লেখকদের উৎসাহিত করে যাতে তারা ব্যবহারকারীর দৃষ্টিকোণ থেকে চিন্তা করেন - অ্যাপ্লিকেশন ব্যবহার করার সময় ব্যবহারকারী কী করতে পারেন - UI এলিমেন্ট খুঁজে বের করা এবং সেগুলির সাথে ইন্টার‍্যাক্ট করা। একই সাথে, ফ্রেমওয়ার্কটি অ্যাক্টিভিটি এবং অ্যাপ্লিকেশনের ভিউতে সরাসরি অ্যাক্সেস প্রতিরোধ করে, কারণ এই অবজেক্টগুলি ধরে রাখা এবং UI থ্রেডের বাইরে এগুলি অপারেট করা টেস্ট ফ্লেকিনেসের একটি প্রধান উৎস। তাই, Espresso API-তে আপনি getView() এবং getCurrentActivity()-এর মতো পদ্ধতি দেখতে পাবেন না। আপনি এখনও ViewAction এবং ViewAssertion-এর নিজস্ব সাবক্লাস প্রয়োগ করে নিরাপদে ভিউ অপারেট করতে পারবেন।

API কম্পোনেন্ট

Espresso-এর প্রধান কম্পোনেন্টগুলির মধ্যে নিম্নলিখিতগুলি অন্তর্ভুক্ত:

  • Espresso – ভিউয়ের সাথে ইন্টার‍্যাকশনের এন্ট্রি পয়েন্ট (onView() এবং onData()-এর মাধ্যমে)। এছাড়াও, এমন API দেখায় যা কোনও ভিউয়ের সাথে যুক্ত নয়, যেমন pressBack()।
  • ViewMatchers – অবজেক্টের একটি সংগ্রহ যা Matcher<? super View> ইন্টারফেস প্রয়োগ করে। বর্তমান ভিউ হায়ারার্কির মধ্যে কোনও ভিউ লোকেট করতে, আপনি এগুলির মধ্যে এক বা একাধিক onView() পদ্ধতিতে পাস করতে পারবেন।
  • ViewActions – ViewAction অবজেক্টের একটি সংগ্রহ যা ViewInteraction.perform() পদ্ধতিতে পাস করা যেতে পারে, যেমন click()।
  • ViewAssertions – ViewAssertion অবজেক্টের একটি সংগ্রহ যা ViewInteraction.check() পদ্ধতিতে পাস করা যেতে পারে। বেশিরভাগ সময়, আপনি matches অ্যাসারশন ব্যবহার করবেন, যা বর্তমানে বেছে নেওয়া ভিউয়ের স্ট্যাটাস অ্যাসার্ট করতে ভিউ ম্যাচ করার টুল ব্যবহার করে।

উদাহরণ:

Kotlin

// withId(R.id.my_view) is a ViewMatcher
// click() is a ViewAction
// matches(isDisplayed()) is a ViewAssertion
onView(withId(R.id.my_view))
    .perform(click())
    .check(matches(isDisplayed()))

জাভা

// withId(R.id.my_view) is a ViewMatcher
// click() is a ViewAction
// matches(isDisplayed()) is a ViewAssertion
onView(withId(R.id.my_view))
    .perform(click())
    .check(matches(isDisplayed()));

ভিউ খুঁজুন

বেশিরভাগ ক্ষেত্রে, onView() পদ্ধতি একটি হ্যামক্রেস্ট ম্যাচিং নেয় যা বর্তমান ভিউ হায়ারার্কির মধ্যে একটি — এবং শুধুমাত্র একটি — ভিউয়ের সাথে মিলবে বলে আশা করা হয়। ম্যাচারগুলি শক্তিশালী এবং যারা Mockito বা JUnit-এর সাথে ব্যবহার করেছেন তাদের কাছে পরিচিত হবে। আপনি যদি হ্যামক্রেস্ট ম্যাচারের সাথে পরিচিত না হন, তাহলে আমরা সাজেস্ট করি যে আপনি এই প্রেজেন্টেশনটি দ্রুত দেখে শুরু করুন।

প্রায়ই কাঙ্খিত ভিউতে একটি অনন্য R.id থাকে এবং একটি সাধারণ withId ম্যাচিং ভিউ সার্চকে আরও নির্দিষ্ট করে তুলবে। তবে, এমন অনেক বৈধ পরিস্থিতি আছে যেখানে আপনি টেস্ট ডেভেলপমেন্টের সময় R.id নির্ধারণ করতে পারবেন না। যেমন, নির্দিষ্ট ভিউতে R.id নাও থাকতে পারে অথবা R.id অনন্য নয়। এর ফলে সাধারণ ইন্সট্রুমেন্টেশন টেস্ট ভঙ্গুর এবং জটিল হয়ে যেতে পারে, কারণ ভিউ অ্যাক্সেস করার সাধারণ উপায়—findViewById()-এর মাধ্যমে—কাজ করে না। তাই, আপনাকে অ্যাক্টিভিটি বা ফ্র্যাগমেন্টের ব্যক্তিগত মেম্বারদের অ্যাক্সেস করতে হতে পারে, যারা ভিউ হোল্ড করে আছে অথবা পরিচিত R.id সহ একটি কন্টেনার খুঁজে বের করতে হতে পারে এবং নির্দিষ্ট ভিউয়ের জন্য এর কন্টেন্টে নেভিগেট করতে হতে পারে।

Espresso এই সমস্যাটি পরিষ্কারভাবে সমাধান করে, আপনাকে ভিউটি সংকীর্ণ করার অনুমতি দেয় বিদ্যমান ViewMatcher অবজেক্ট বা আপনার নিজস্ব কাস্টম অবজেক্ট ব্যবহার করে।

R.id-এর মাধ্যমে কোনও ভিউ খোঁজা onView() কল করার মতোই সহজ:

Kotlin

onView(withId(R.id.my_view))

জাভা

onView(withId(R.id.my_view));

কখনও কখনও, একাধিক ভিউয়ের মধ্যে R.id ভ্যালু শেয়ার করা হয়। এটি হলে, নির্দিষ্ট R.id ব্যবহার করার চেষ্টা করলে আপনাকে ব্যতিক্রম দেখায়, যেমন AmbiguousViewMatcherException। ব্যতিক্রম মেসেজ আপনাকে বর্তমান ভিউ হায়ারার্কির টেক্সট প্রতিনিধিত্ব প্রদান করে, যা আপনি সার্চ করতে পারেন এবং অনন্য নয় এমন R.id-এর সাথে ম্যাচ করে এমন ভিউ খুঁজে পেতে পারেন:

java.lang.RuntimeException:
androidx.test.espresso.AmbiguousViewMatcherException
This matcher matches multiple views in the hierarchy: (withId: is <123456789>)

...

+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=false, enabled=true,
selected=false, is-layout-requested=false, text=,
root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}
****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=true, enabled=true,
selected=false, is-layout-requested=false, text=Hello!,
root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}
****MATCHES****

ভিউয়ের বিভিন্ন অ্যাট্রিবিউট দেখে, আপনি অনন্যভাবে শনাক্তযোগ্য প্রপার্টি খুঁজে পেতে পারেন। উপরের উদাহরণে, একটি ভিউতে এই টেক্সট আছে "Hello!"। আপনি কম্বিনেশন ম্যাচিং ব্যবহার করে আপনার সার্চ আরও ছোট করতে এটি ব্যবহার করতে পারেন:

Kotlin

onView(allOf(withId(R.id.my_view), withText("Hello!")))

জাভা

onView(allOf(withId(R.id.my_view), withText("Hello!")));

এছাড়াও, আপনি কোনও ম্যাচিংয়ের নিয়ম রিভার্স না করার বিকল্প বেছে নিতে পারেন:

Kotlin

onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))))

জাভা

onView(allOf(withId(R.id.my_view), not(withText("Unwanted"))));

Espresso-এর প্রদান করা ভিউ ম্যাচারের জন্য ViewMatchers দেখুন।

বিবেচ্য বিষয়

  • একটি ভালভাবে কাজ করা অ্যাপ্লিকেশনে, ব্যবহারকারী ইন্টার‍্যাক্ট করতে পারেন এমন সব ভিউতে বর্ণনামূলক টেক্সট বা কন্টেন্টের বিবরণ থাকা উচিত। আরও বিবরণের জন্য অ্যাপ আরও অ্যাক্সেসযোগ্য করা দেখুন। আপনি যদি withText() বা withContentDescription() ব্যবহার করে সার্চের ফলাফল আরও নির্দিষ্ট করতে না পারেন, তাহলে এটিকে অ্যাক্সেসিবিলিটি সংক্রান্ত সমস্যা হিসেবে বিবেচনা করুন।
  • আপনি যে ভিউ খুঁজছেন সেটি খুঁজে পেতে সবচেয়ে কম বর্ণনামূলক ম্যাচিং ব্যবহার করুন। অতিরিক্ত স্পেসিফাই করবেন না কারণ এর ফলে ফ্রেমওয়ার্ককে প্রয়োজনের চেয়ে বেশি কাজ করতে হবে। যেমন, কোনও ভিউ যদি তার টেক্সট দ্বারা অনন্যভাবে শনাক্তযোগ্য হয়, তাহলে আপনাকে উল্লেখ করতে হবে না যে ভিউটি TextView থেকেও অ্যাসাইন করা যেতে পারে। অনেক ভিউয়ের জন্য ভিউয়ের R.id যথেষ্ট হওয়া উচিত।
  • টার্গেট ভিউ যদি AdapterView-এর মধ্যে থাকে—যেমন ListView, GridView, বা Spinner—তাহলে onView() পদ্ধতি কাজ নাও করতে পারে। এইসব ক্ষেত্রে, আপনাকে এর পরিবর্তে onData() ব্যবহার করতে হবে।

কোনও ভিউতে অ্যাকশন পারফর্ম করুন

টার্গেট ভিউয়ের জন্য উপযুক্ত ম্যাচ খুঁজে পেলে, পারফর্ম পদ্ধতি ব্যবহার করে এটির উপর ViewAction-এর ইনস্ট্যান্স পারফর্ম করা সম্ভব।

যেমন, ভিউতে ক্লিক করতে:

Kotlin

onView(...).perform(click())

জাভা

onView(...).perform(click());

আপনি একটি পারফর্ম কলের মাধ্যমে একাধিক অ্যাকশন এক্সিকিউট করতে পারবেন:

Kotlin

onView(...).perform(typeText("Hello"), click())

জাভা

onView(...).perform(typeText("Hello"), click());

আপনি যে ভিউ নিয়ে কাজ করছেন সেটি যদি ScrollView (ভার্টিক্যাল বা হরাইজন্টাল)-এর মধ্যে থাকে, তাহলে ভিউ দেখানোর জন্য প্রয়োজনীয় পূর্ববর্তী অ্যাকশনগুলি—যেমন click() এবং typeText()—scrollTo()-এর সাথে বিবেচনা করুন। এটি নিশ্চিত করে যে অন্য অ্যাকশনে যাওয়ার আগে ভিউ দেখানো হয়েছে:

Kotlin

onView(...).perform(scrollTo(), click())

জাভা

onView(...).perform(scrollTo(), click());

Espresso-এর মাধ্যমে প্রদান করা ভিউ অ্যাকশনের জন্য ViewActions দেখুন।

ভিউ অ্যাসার্শন চেক করুন

check() পদ্ধতির মাধ্যমে বর্তমানে বেছে নেওয়া ভিউতে অ্যাসার্শন প্রয়োগ করা যেতে পারে। সবচেয়ে বেশি ব্যবহৃত অ্যাসার্শন হল matches() অ্যাসার্শন। বর্তমানে বেছে নেওয়া ভিউয়ের অবস্থা নিশ্চিত করতে এটি ViewMatcher অবজেক্ট ব্যবহার করে।

যেমন, কোনও ভিউতে "Hello!" টেক্সট আছে কিনা তা চেক করতে:

Kotlin

onView(...).check(matches(withText("Hello!")))

জাভা

onView(...).check(matches(withText("Hello!")));

আপনি যদি দাবি করতে চান যে "Hello!" হল ভিউয়ের কন্টেন্ট, তাহলে নিম্নলিখিত বিষয়গুলি খারাপ পদ্ধতি হিসেবে বিবেচনা করা হয়:

Kotlin

// Don't use assertions like withText inside onView.
onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()))

জাভা

// Don't use assertions like withText inside onView.
onView(allOf(withId(...), withText("Hello!"))).check(matches(isDisplayed()));

অন্যদিকে, আপনি যদি নিশ্চিত করতে চান যে "Hello!" টেক্সট সহ ভিউটি দেখা যাচ্ছে—যেমন, ভিউয়ের দৃশ্যমানতা ফ্ল্যাগ পরিবর্তন করার পরে—তাহলে কোডটি ঠিক আছে।

অ্যাসার্শন সিম্পল টেস্ট দেখুন

এই উদাহরণে, SimpleActivity-এ একটি Button এবং একটি TextView আছে। TextView-এর কন্টেন্ট পরিবর্তন করে "Hello Espresso!" করতে বোতামে ক্লিক করুন।

Espresso-এর মাধ্যমে এটি কীভাবে পরীক্ষা করবেন তা এখানে দেওয়া হল:

বোতামে ক্লিক করুন

প্রথম ধাপ হল এমন একটি প্রপার্টি খোঁজা যা বোতামটি খুঁজে পেতে সাহায্য করে। SimpleActivity-এ বোতামটির একটি অনন্য R.id আছে, যেমনটি প্রত্যাশিত।

Kotlin

onView(withId(R.id.button_simple))

জাভা

onView(withId(R.id.button_simple));

এখন ক্লিক করতে:

Kotlin

onView(withId(R.id.button_simple)).perform(click())

জাভা

onView(withId(R.id.button_simple)).perform(click());

TextView টেক্সট যাচাই করুন

যাচাই করার জন্য টেক্সট সহ TextView-এর একটি অনন্য R.id-ও আছে:

Kotlin

onView(withId(R.id.text_simple))

জাভা

onView(withId(R.id.text_simple));

এখন কন্টেন্ট টেক্সট যাচাই করতে:

Kotlin

onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")))

জাভা

onView(withId(R.id.text_simple)).check(matches(withText("Hello Espresso!")));

অ্যাডাপ্টার ভিউতে ডেটা লোড হচ্ছে কিনা তা চেক করুন

AdapterView হল বিশেষ ধরনের উইজেট যা অ্যাডাপ্টার থেকে ডায়নামিক উপায়ে ডেটা লোড করে। AdapterView-এর সবচেয়ে সাধারণ উদাহরণ হল ListView। LinearLayout-এর মতো স্ট্যাটিক উইজেটের বিপরীতে, AdapterView চাইল্ডের শুধুমাত্র একটি সাবসেট বর্তমান ভিউ হায়ারার্কিতে লোড করা হতে পারে। একটি সাধারণ onView() সার্চ করলে বর্তমানে লোড করা নেই এমন ভিউ খুঁজে পাওয়া যাবে না।

Espresso একটি পৃথক onData() এন্ট্রি পয়েন্ট প্রদান করে এটি পরিচালনা করে যা প্রথমে প্রশ্ন করা অ্যাডাপ্টার আইটেমটি লোড করতে সক্ষম, এটিতে বা এর যেকোনও চাইল্ডে কাজ করার আগে এটিকে ফোকাসে নিয়ে আসে।

সতর্কতা: AdapterView-এর কাস্টম প্রয়োগের ক্ষেত্রে onData() পদ্ধতির সাথে সমস্যা হতে পারে, যদি সেগুলি ইনহেরিটেন্স চুক্তি লঙ্ঘন করে, বিশেষ করে getItem() API। এই ধরনের ক্ষেত্রে, সবচেয়ে ভাল উপায় হল আপনার অ্যাপ্লিকেশন কোড রিফ্যাক্টর করা। আপনি যদি তা করতে না পারেন, তাহলে আপনি একটি ম্যাচিং কাস্টম AdapterViewProtocol প্রয়োগ করতে পারেন। আরও তথ্যের জন্য, Espresso-এর মাধ্যমে প্রদান করা ডিফল্ট AdapterViewProtocols ক্লাস দেখুন।

অ্যাডাপ্টার ভিউ সাধারণ টেস্ট

এই সহজ টেস্ট থেকে বোঝা যায় যে onData() কীভাবে ব্যবহার করতে হয়। SimpleActivity-এ একটি Spinner আছে যাতে কয়েকটি আইটেম আছে যা কফি পানীয়ের ধরনকে দেখায়। কোনও আইটেম বেছে নেওয়া হলে, TextView পরিবর্তিত হয়ে "One %s a day!" হয়ে যায়, যেখানে %s বেছে নেওয়া আইটেমকে দেখায়।

এই পরীক্ষার লক্ষ্য হল Spinner খোলা, একটি নির্দিষ্ট আইটেম বেছে নেওয়া এবং TextView-এ আইটেমটি আছে কিনা তা যাচাই করা। Spinner ক্লাস AdapterView-এর উপর ভিত্তি করে তৈরি হওয়ায়, আইটেম ম্যাচ করার জন্য onView()-এর পরিবর্তে onData() ব্যবহার করার সাজেশন দেওয়া হয়।

আইটেম বেছে নেওয়ার বিকল্প খুলুন

Kotlin

onView(withId(R.id.spinner_simple)).perform(click())

জাভা

onView(withId(R.id.spinner_simple)).perform(click());

একটি আইটেম বেছে নিন

আইটেম বেছে নেওয়ার জন্য, Spinner তার কন্টেন্ট সহ একটি ListView তৈরি করে। এই ভিউটি খুব দীর্ঘ হতে পারে এবং এলিমেন্টটি ভিউ হায়ারার্কিতে কন্ট্রিবিউট নাও করতে পারে। onData() ব্যবহার করে আমরা ভিউ হায়ারার্কিতে আমাদের পছন্দসই এলিমেন্ট দেখাতে বাধ্য করি। Spinner-এর আইটেমগুলি স্ট্রিং, তাই আমরা এমন একটি আইটেম মেলাতে চাই যা স্ট্রিং "Americano"-এর সমান:

Kotlin

onData(allOf(`is`(instanceOf(String::class.java)),
        `is`("Americano"))).perform(click())

জাভা

onData(allOf(is(instanceOf(String.class)), is("Americano"))).perform(click());

টেক্সট সঠিক কিনা তা যাচাই করুন

Kotlin

onView(withId(R.id.spinnertext_simple))
    .check(matches(withText(containsString("Americano"))))

জাভা

onView(withId(R.id.spinnertext_simple))
    .check(matches(withText(containsString("Americano"))));

ডিবাগিং

কোনও টেস্ট ব্যর্থ হলে Espresso ডিবাগিং সংক্রান্ত প্রয়োজনীয় তথ্য প্রদান করে:

লগিং

Espresso সব ভিউ অ্যাকশন logcat-এ লগ করে। যেমন:

ViewInteraction: Performing 'single click' action on view with text: Espresso

ভিউ হায়ারার্কি

onView() ব্যর্থ হলে Espresso ব্যতিক্রম মেসেজে ভিউ হায়ারার্কি প্রিন্ট করে।

  • onView() টার্গেট ভিউ খুঁজে না পেলে, NoMatchingViewException থ্রো করা হয়। ম্যাচার কেন কোনও ভিউয়ের সাথে ম্যাচ করেনি তা বিশ্লেষণ করতে আপনি ব্যতিক্রম স্ট্রিংয়ে ভিউ হায়ারার্কি পরীক্ষা করতে পারেন।
  • onView() যদি প্রদত্ত ম্যাচারের সাথে মেলে এমন একাধিক ভিউ খুঁজে পায়, তাহলে একটি AmbiguousViewMatcherException থ্রো করা হয়। ভিউ হায়ারার্কি প্রিন্ট করা হয় এবং মিলে যাওয়া সব ভিউ MATCHES লেবেল দিয়ে চিহ্নিত করা হয়:
java.lang.RuntimeException:
androidx.test.espresso.AmbiguousViewMatcherException
This matcher matches multiple views in the hierarchy: (withId: is <123456789>)

...

+----->SomeView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=false, enabled=true,
selected=false, is-layout-requested=false, text=,
root-is-layout-requested=false, x=0.0, y=625.0, child-count=1}
****MATCHES****
|
+------>OtherView{id=123456789, res-name=plus_one_standard_ann_button,
visibility=VISIBLE, width=523, height=48, has-focus=false, has-focusable=true,
window-focus=true, is-focused=false, is-focusable=true, enabled=true,
selected=false, is-layout-requested=false, text=Hello!,
root-is-layout-requested=false, x=0.0, y=0.0, child-count=1}
****MATCHES****

জটিল ভিউ হায়ারার্কি বা উইজেটের অপ্রত্যাশিত আচরণ নিয়ে কাজ করার সময় ব্যাখ্যার জন্য Android Studio-তে হায়ারার্কি ভিউয়ার ব্যবহার করা সবসময় সহায়ক হয়।

অ্যাডাপ্টার ভিউ সংক্রান্ত সতর্কতা

Espresso ব্যবহারকারীদের AdapterView উইজেটের উপস্থিতি সম্পর্কে সতর্ক করে। যখন কোনও onView() অপারেশন NoMatchingViewException থ্রো করে এবং ভিউ হায়ারার্কিতে AdapterView উইজেট উপস্থিত থাকে, তখন সবচেয়ে সাধারণ সমাধান হল onData() ব্যবহার করা। ব্যতিক্রম সংক্রান্ত মেসেজে অ্যাডাপ্টার ভিউয়ের তালিকা সহ একটি সতর্কতা অন্তর্ভুক্ত থাকবে। টার্গেট ভিউ লোড করার জন্য onData()-কে কল করতে আপনি এই তথ্য ব্যবহার করতে পারেন।

অতিরিক্ত রিসোর্স

Android টেস্টে Espresso ব্যবহার করার ব্যাপারে আরও তথ্য পেতে, নিম্নলিখিত রিসোর্স দেখুন।

নমুনা

  • CustomMatcherSample: EditText অবজেক্টের হিন্ট প্রপার্টি ম্যাচ করার জন্য Espresso কীভাবে এক্সটেন্ড করতে হয় তা দেখায়।
  • RecyclerViewSample: Espresso-এর জন্য RecyclerViewটি অ্যাকশন।
  • (আরও...)