Compose টেস্টিং API-এর v2 সংস্করণগুলি ( createComposeRule , createAndroidComposeRule , runComposeUiTest , runAndroidComposeUiTest , ইত্যাদি) এখন কোরোটিন এক্সিকিউশনের উপর নিয়ন্ত্রণ উন্নত করার জন্য উপলব্ধ। এই আপডেটটি সম্পূর্ণ API পৃষ্ঠের নকল করে না; শুধুমাত্র পরীক্ষার পরিবেশ স্থাপনকারী API গুলি আপডেট করা হয়েছে।
v1 API গুলি বন্ধ করে দেওয়া হয়েছে, এবং নতুন API গুলিতে মাইগ্রেট করার জন্য জোরালোভাবে সুপারিশ করা হচ্ছে। মাইগ্রেট করলে আপনার পরীক্ষাগুলি স্ট্যান্ডার্ড কোরোটিন আচরণের সাথে সামঞ্জস্যপূর্ণ কিনা তা যাচাই করা হয় এবং ভবিষ্যতের সামঞ্জস্যের সমস্যাগুলি এড়ানো যায়। বন্ধ করে দেওয়া v1 API গুলির তালিকার জন্য, API ম্যাপিং দেখুন।
এই পরিবর্তনগুলি androidx.compose.ui:ui-test-junit4:1.11.0-alpha03+ এবং androidx.compose.ui:ui-test:1.11.0-alpha03+ এ অন্তর্ভুক্ত।
যদিও v1 API গুলি UnconfinedTestDispatcher এর উপর নির্ভর করত, v2 API গুলি চলমান কম্পোজিশনের জন্য ডিফল্টরূপে StandardTestDispatcher ব্যবহার করে। এই পরিবর্তনটি Compose পরীক্ষার আচরণকে স্ট্যান্ডার্ড runTest API গুলির সাথে সারিবদ্ধ করে এবং coroutine এক্সিকিউশন অর্ডারের উপর স্পষ্ট নিয়ন্ত্রণ প্রদান করে।
এপিআই ম্যাপিং
v2 API তে আপগ্রেড করার সময়, আপনি সাধারণত প্যাকেজ আমদানি আপডেট করতে এবং নতুন ডিসপ্যাচার পরিবর্তনগুলি গ্রহণ করতে Find + Replace ব্যবহার করতে পারেন।
বিকল্পভাবে, নিম্নলিখিত প্রম্পট ব্যবহার করে জেমিনিকে কম্পোজ টেস্টিং API-এর v2-তে মাইগ্রেশন করতে বলুন:
এই প্রম্পটটি v2 টেস্টিং API-তে মাইগ্রেট করার জন্য এই নির্দেশিকাটি ব্যবহার করবে। AI প্রম্পট
v1 টেস্টিং API থেকে v2 টেস্টিং API-তে স্থানান্তর করুন
Migrate to Compose testing v2 APIs using the official
migration guide.
অবচিত v1 API গুলিকে তাদের v2 প্রতিস্থাপনের সাথে ম্যাপ করতে নিম্নলিখিত টেবিলটি ব্যবহার করুন:
অবচিত (v1) | প্রতিস্থাপন (v2) |
|---|---|
| |
| |
| |
| |
| |
| |
| |
|
পশ্চাদমুখী সামঞ্জস্য এবং ব্যতিক্রম
বিদ্যমান v1 API গুলি এখন অবচিত, কিন্তু বিদ্যমান আচরণ বজায় রাখতে এবং পরিবর্তনগুলি ভাঙা রোধ করতে UnconfinedTestDispatcher ব্যবহার করা চালিয়ে যাচ্ছে।
নিম্নলিখিতটি একমাত্র ব্যতিক্রম যেখানে ডিফল্ট আচরণ পরিবর্তিত হয়েছে:
AndroidComposeUiTestEnvironment ক্লাসে কম্পোজিশন চালানোর জন্য ব্যবহৃত ডিফল্ট টেস্ট ডিসপ্যাচারটি UnconfinedTestDispatcher থেকে StandardTestDispatcher এ স্যুইচ করা হয়েছে। এটি সেই ক্ষেত্রে প্রভাবিত করে যেখানে আপনি কনস্ট্রাক্টর, অথবা সাবক্লাস AndroidComposeUiTestEnvironment ব্যবহার করে একটি ইনস্ট্যান্স তৈরি করেন এবং সেই কনস্ট্রাক্টরটিকে কল করেন।
মূল পরিবর্তন: কোরোটিন কার্যকর করার উপর প্রভাব
API গুলির v1 এবং v2 এর মধ্যে প্রাথমিক পার্থক্য হল কোরোটিনগুলি কীভাবে প্রেরণ করা হয়:
- v1 API (
UnconfinedTestDispatcher): যখন একটি coroutine চালু করা হত, তখন এটি বর্তমান থ্রেডে তাৎক্ষণিকভাবে কার্যকর হত, প্রায়শই পরবর্তী লাইনের টেস্ট কোড চালানোর আগেই শেষ হত। প্রোডাকশন আচরণের বিপরীতে, এই তাৎক্ষণিক কার্যকরকরণ অসাবধানতাবশত একটি লাইভ অ্যাপ্লিকেশনে ঘটতে পারে এমন বাস্তব সময়ের সমস্যা বা রেসের পরিস্থিতিকে আড়াল করতে পারে। - v2 API (
StandardTestDispatcher): যখন একটি coroutine চালু করা হয়, তখন এটি সারিবদ্ধ থাকে এবং পরীক্ষাটি স্পষ্টভাবে ভার্চুয়াল ঘড়িতে অগ্রসর না হওয়া পর্যন্ত কার্যকর হয় না। স্ট্যান্ডার্ড কম্পোজ টেস্ট API (যেমনwaitForIdle()) ইতিমধ্যেই এই সিঙ্ক্রোনাইজেশন পরিচালনা করে, তাই এই স্ট্যান্ডার্ড API গুলির উপর নির্ভর করে বেশিরভাগ পরীক্ষা কোনও পরিবর্তন ছাড়াই কাজ চালিয়ে যাওয়া উচিত।
সাধারণ ব্যর্থতা এবং সেগুলি কীভাবে ঠিক করা যায়
যদি v2 তে আপগ্রেড করার পরে আপনার পরীক্ষাগুলি ব্যর্থ হয়, তাহলে সম্ভবত সেগুলি নিম্নলিখিত প্যাটার্নটি প্রদর্শন করবে:
- ব্যর্থতা : আপনি একটি টাস্ক চালু করেন (উদাহরণস্বরূপ, একটি ViewModel ডেটা লোড করে), কিন্তু আপনার দাবি অবিলম্বে ব্যর্থ হয় কারণ ডেটা এখনও "লোড হচ্ছে" অবস্থায় থাকে।
- কারণ : v2 API-এর ক্ষেত্রে, কোরোটিনগুলি তাৎক্ষণিকভাবে কার্যকর করার পরিবর্তে সারিবদ্ধ থাকে। কাজটি সারিবদ্ধ ছিল কিন্তু ফলাফল পরীক্ষা করার আগে আসলে কখনও চালানো হয়নি।
- ঠিক করুন : স্পষ্টভাবে সময় এগিয়ে দিন। কখন কাজ সম্পাদন করতে হবে তা আপনাকে অবশ্যই v2 ডিসপ্যাচারকে স্পষ্টভাবে জানাতে হবে।
পূর্ববর্তী পদ্ধতি
v1-এ, কাজটি তাৎক্ষণিকভাবে শুরু এবং শেষ হয়ে যায়। v2-তে, নিম্নলিখিত কোডটি ব্যর্থ হয় কারণ loadData() এখনও বাস্তবে রান করেনি।
// In v1, this launched and finished immediately.
viewModel.loadData()
// In v2, this fails because loadData() hasn't actually run yet!
assertEquals(Success, viewModel.state.value)
প্রস্তাবিত পদ্ধতি
দাবি করার আগে সারিবদ্ধ কাজগুলি সম্পাদন করতে waitForIdle অথবা runOnIdle ব্যবহার করুন।
বিকল্প ১ : waitForIdle ব্যবহার করে UI নিষ্ক্রিয় না হওয়া পর্যন্ত ঘড়িটি এগিয়ে যায়, কোরোটিন চালু হয়েছে কিনা তা যাচাই করে।
viewModel.loadData()
// Explicitly run all queued tasks
composeTestRule.waitForIdle()
assertEquals(Success, viewModel.state.value)
বিকল্প ২ : UI নিষ্ক্রিয় হয়ে যাওয়ার পরে runOnIdle ব্যবহার করলে UI থ্রেডে কোড ব্লকটি কার্যকর হয়।
viewModel.loadData()
// Run the assertion after the UI is idle
composeTestRule.runOnIdle {
assertEquals(Success, viewModel.state.value)
}
ম্যানুয়াল সিঙ্ক্রোনাইজেশন
ম্যানুয়াল সিঙ্ক্রোনাইজেশনের ক্ষেত্রে, যেমন যখন অটো-অ্যাডভান্সিং অক্ষম করা হয়, তখন একটি কোরোটিন চালু করলে তাৎক্ষণিকভাবে কার্যকর হয় না কারণ টেস্ট ক্লকটি বিরতি দেওয়া হয়। ভার্চুয়াল ক্লকটি অগ্রসর না করে কিউতে কোরোটিনগুলি কার্যকর করতে, runCurrent() API ব্যবহার করুন। এটি বর্তমান ভার্চুয়াল সময়ের জন্য নির্ধারিত কাজগুলি চালায়।
composeTestRule.mainClock.scheduler.runCurrent()
waitForIdle() এর বিপরীতে, যা UI স্থিতিশীল না হওয়া পর্যন্ত পরীক্ষার ঘড়িকে এগিয়ে নিয়ে যায়, runCurrent() বর্তমান ভার্চুয়াল সময় বজায় রেখে মুলতুবি থাকা কাজগুলি সম্পাদন করে। এই আচরণটি মধ্যবর্তী অবস্থাগুলির যাচাইকরণ সক্ষম করে যা অন্যথায় ঘড়িটিকে নিষ্ক্রিয় অবস্থায় অগ্রসর করা হলে এড়িয়ে যেত।
পরীক্ষার পরিবেশে ব্যবহৃত অন্তর্নিহিত পরীক্ষার সময়সূচীটি উন্মুক্ত করা হয়েছে। এই সময়সূচীটি পরীক্ষার ঘড়িটি সিঙ্ক্রোনাইজ করার জন্য Kotlin runTest API এর সাথে একত্রে ব্যবহার করা যেতে পারে।
runComposeUiTest এ স্থানান্তর করুন
যদি আপনি Kotlin runTest API-এর পাশাপাশি Compose test API ব্যবহার করেন, তাহলে runComposeUiTest এ স্যুইচ করার জন্য জোরালোভাবে পরামর্শ দেওয়া হচ্ছে।
পূর্ববর্তী পদ্ধতি
createComposeRule এবং runTest ব্যবহার করলে দুটি পৃথক ঘড়ি তৈরি হয়: একটি Compose এর জন্য এবং একটি test coroutine scope এর জন্য। এই কনফিগারেশন আপনাকে টেস্ট শিডিউলারটি ম্যানুয়ালি সিঙ্ক্রোনাইজ করতে বাধ্য করতে পারে।
@get:Rule val composeTestRule = createComposeRule() @Test fun testWithCoroutines() { composeTestRule.setContent { var status by remember { mutableStateOf("Loading...") } LaunchedEffect(Unit) { delay(1000) status = "Done!" } Text(text = status) } // NOT RECOMMENDED // Fails: runTest creates a new, separate scheduler. // Advancing time here does NOT advance the compose clock. // To fix this without migrating, you would need to share the scheduler // by passing 'composeTestRule.mainClock.scheduler' to runTest. runTest { composeTestRule.onNodeWithText("Loading...").assertIsDisplayed() advanceTimeBy(1000) composeTestRule.onNodeWithText("Done!").assertIsDisplayed() } }
প্রস্তাবিত পদ্ধতি
runComposeUiTest API স্বয়ংক্রিয়ভাবে আপনার টেস্ট ব্লকটিকে তার নিজস্ব runTest স্কোপের মধ্যে কার্যকর করে। টেস্ট ক্লকটি কম্পোজ এনভায়রনমেন্টের সাথে সিঙ্ক্রোনাইজ করা হয়, তাই আপনাকে আর শিডিউলার ম্যানুয়ালি পরিচালনা করতে হবে না।
@Test fun testWithCoroutines() = runComposeUiTest { setContent { var status by remember { mutableStateOf("Loading...") } LaunchedEffect(Unit) { delay(1000) status = "Done!" } Text(text = status) } onNodeWithText("Loading...").assertIsDisplayed() mainClock.advanceTimeBy(1000 + 16 /* Frame buffer */) onNodeWithText("Done!").assertIsDisplayed() } }