अब Compose के टेस्टिंग एपीआई के v2 वर्शन (createComposeRule,
createAndroidComposeRule, runComposeUiTest,
runAndroidComposeUiTest वगैरह) उपलब्ध हैं. इनसे, कोराटीन के एक्ज़ीक्यूशन को बेहतर तरीके से कंट्रोल किया जा सकता है. इस अपडेट से, पूरे एपीआई सरफेस को डुप्लीकेट नहीं किया जाता है. सिर्फ़ उन एपीआई को अपडेट किया गया है जो टेस्ट एनवायरमेंट बनाते हैं.
v1 API बंद कर दिए गए हैं. हमारा सुझाव है कि आप नए API पर माइग्रेट करें. माइग्रेट करने से यह पुष्टि होती है कि आपकी जांच, स्टैंडर्ड कोरूटीन के व्यवहार के मुताबिक हैं. साथ ही, इससे आने वाले समय में कंपैटिबिलिटी से जुड़ी समस्याएं नहीं होती हैं. बंद किए गए v1 एपीआई की सूची देखने के लिए, एपीआई मैपिंग देखें.
ये बदलाव androidx.compose.ui:ui-test-junit4:1.11.0-alpha03+ और androidx.compose.ui:ui-test:1.11.0-alpha03+ में शामिल हैं.
v1 एपीआई, UnconfinedTestDispatcher पर निर्भर करते थे. वहीं, v2 एपीआई, कंपोज़िशन चलाने के लिए डिफ़ॉल्ट रूप से StandardTestDispatcher का इस्तेमाल करते हैं. इस बदलाव से, Compose टेस्ट का तरीका, स्टैंडर्ड runTest एपीआई के साथ अलाइन हो जाता है. साथ ही, इससे कोरूटीन के एक्ज़ीक्यूशन के क्रम पर साफ़ तौर पर कंट्रोल मिलता है.
एपीआई मैपिंग
v2 एपीआई पर अपग्रेड करते समय, आम तौर पर ढूंढें और बदलें सुविधा का इस्तेमाल करके, पैकेज इंपोर्ट अपडेट किए जा सकते हैं. साथ ही, डिस्पैचर में किए गए नए बदलावों को अपनाया जा सकता है.
इसके अलावा, Gemini से Compose टेस्टिंग एपीआई के v2 पर माइग्रेट करने के लिए कहें. इसके लिए, यह प्रॉम्प्ट इस्तेमाल करें:
एआई प्रॉम्प्ट
टेस्टिंग के लिए इस्तेमाल किए जाने वाले v1 एपीआई से टेस्टिंग के लिए इस्तेमाल किए जाने वाले v2 एपीआई पर माइग्रेट करना
यह प्रॉम्प्ट, v2 टेस्टिंग एपीआई पर माइग्रेट करने के लिए इस गाइड का इस्तेमाल करेगा.
Migrate to Compose testing v2 APIs using the official
migration guide.सेवा में नहीं रहे v1 एपीआई को उनके v2 वर्शन में मैप करने के लिए, यहां दी गई टेबल का इस्तेमाल करें:
अब सेवा में नहीं है (v1) |
बदला गया वर्शन (v2) |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
पिछले वर्शन के साथ काम करने की सुविधा और अपवाद
मौजूदा v1 एपीआई अब काम नहीं करते. हालांकि, मौजूदा व्यवहार को बनाए रखने और बड़े बदलावों को रोकने के लिए, UnconfinedTestDispatcher का इस्तेमाल जारी रखें.
यहां सिर्फ़ एक ऐसा अपवाद दिया गया है जहां डिफ़ॉल्ट व्यवहार में बदलाव किया गया है:
AndroidComposeUiTestEnvironment क्लास में कंपोज़िशन चलाने के लिए इस्तेमाल किए जाने वाले डिफ़ॉल्ट टेस्ट डिस्पैचर को UnconfinedTestDispatcher से बदलकर StandardTestDispatcher कर दिया गया है. इसका असर उन मामलों पर पड़ता है जहां कंस्ट्रक्टर का इस्तेमाल करके कोई इंस्टेंस बनाया जाता है या सबक्लास AndroidComposeUiTestEnvironment बनाया जाता है और उस कंस्ट्रक्टर को कॉल किया जाता है.
मुख्य बदलाव: को-रूटीन के एक्ज़ीक्यूशन पर असर
एपीआई के v1 और v2 के बीच मुख्य अंतर यह है कि कोराउटीन को कैसे भेजा जाता है:
- v1 एपीआई (
UnconfinedTestDispatcher): जब कोई कोरूटीन लॉन्च किया जाता था, तो वह मौजूदा थ्रेड पर तुरंत काम करता था. साथ ही, अक्सर टेस्ट कोड की अगली लाइन के चलने से पहले ही पूरा हो जाता था. प्रोडक्शन के दौरान होने वाले व्यवहार के उलट, इस तुरंत लागू होने वाली सुविधा से अनजाने में समय से जुड़ी असली समस्याएं या रेस की स्थितियां छिप सकती हैं. ये समस्याएं लाइव ऐप्लिकेशन में होती हैं. - v2 एपीआई (
StandardTestDispatcher): जब कोई कोरूटीन लॉन्च किया जाता है, तो उसे कतार में रखा जाता है. यह तब तक काम नहीं करता, जब तक टेस्ट में वर्चुअल क्लॉक को साफ़ तौर पर आगे नहीं बढ़ाया जाता. स्टैंडर्ड कंपोज़ टेस्ट एपीआई (जैसे किwaitForIdle()) पहले से ही इस सिंक्रनाइज़ेशन को मैनेज करते हैं. इसलिए, इन स्टैंडर्ड एपीआई पर निर्भर ज़्यादातर टेस्ट, बिना किसी बदलाव के काम करते रहेंगे.
आम तौर पर होने वाली गड़बड़ियां और उन्हें ठीक करने के तरीके
अगर v2 पर अपग्रेड करने के बाद आपके टेस्ट पूरे नहीं होते हैं, तो हो सकता है कि वे इस पैटर्न के मुताबिक हों:
- असफल: आपने कोई टास्क लॉन्च किया है. उदाहरण के लिए, ViewModel डेटा लोड करता है. हालांकि, डेटा अब भी "लोड हो रहा है" स्थिति में है, इसलिए आपका दावा तुरंत पूरा नहीं हो पाता.
- वजह: v2 एपीआई के साथ, कोराउटीन को तुरंत लागू करने के बजाय, उन्हें लाइन में लगाया जाता है. टास्क को कतार में रखा गया था, लेकिन नतीजे की जांच करने से पहले उसे कभी नहीं चलाया गया.
- ठीक करें: समय को साफ़ तौर पर आगे बढ़ाएं. आपको 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 का इस्तेमाल करने से, यूज़र इंटरफ़ेस (यूआई) के निष्क्रिय होने तक समय आगे बढ़ता है. इससे यह पुष्टि होती है कि कोरूटीन चल रहा है.
viewModel.loadData()
// Explicitly run all queued tasks
composeTestRule.waitForIdle()
assertEquals(Success, viewModel.state.value)
दूसरा विकल्प: runOnIdle का इस्तेमाल करने पर, यूज़र इंटरफ़ेस (यूआई) के आइडल होने के बाद, यूज़र इंटरफ़ेस (यूआई) थ्रेड पर कोड ब्लॉक को एक्ज़ीक्यूट किया जाता है.
viewModel.loadData()
// Run the assertion after the UI is idle
composeTestRule.runOnIdle {
assertEquals(Success, viewModel.state.value)
}
मैन्युअल तरीके से सिंक्रनाइज़ करना
मैन्युअल तरीके से सिंक करने की सुविधा चालू होने पर, जैसे कि ऑटो-ऐडवांसिंग की सुविधा बंद होने पर, कोरूटीन लॉन्च करने से तुरंत कोड नहीं चलता, क्योंकि टेस्ट क्लॉक रुकी हुई होती है. वर्चुअल क्लॉक को आगे बढ़ाए बिना, कतार में मौजूद कोरूटीन को चलाने के लिए, runCurrent() एपीआई का इस्तेमाल करें. यह कुकी, मौजूदा वर्चुअल समय के लिए शेड्यूल किए गए टास्क को पूरा करती है.
composeTestRule.mainClock.scheduler.runCurrent()
waitForIdle(), टेस्ट क्लॉक को तब तक आगे बढ़ाता है, जब तक यूज़र इंटरफ़ेस (यूआई) स्थिर नहीं हो जाता. इसके उलट, runCurrent() मौजूदा वर्चुअल समय को बनाए रखते हुए, लंबित टास्क पूरे करता है. इस सुविधा की मदद से, बीच की उन स्थितियों की पुष्टि की जा सकती है जिन्हें आम तौर पर तब छोड़ दिया जाता है, जब घड़ी को निष्क्रिय स्थिति में ले जाया जाता है.
टेस्ट एनवायरमेंट में इस्तेमाल किए गए टेस्ट शेड्यूलर को दिखाया जाता है. इस शेड्यूलर का इस्तेमाल, Kotlin runTest एपीआई के साथ किया जा सकता है, ताकि टेस्ट क्लॉक को सिंक किया जा सके.
runComposeUiTest पर माइग्रेट करना
अगर Kotlin runTest API के साथ-साथ Compose test API का इस्तेमाल किया जा रहा है, तो हमारा सुझाव है कि आप runComposeUiTest पर स्विच करें.
पिछला तरीका
runTest के साथ createComposeRule का इस्तेमाल करने पर, दो अलग-अलग क्लॉक बनती हैं: एक कंपोज़ के लिए और दूसरी टेस्ट कोरूटीन स्कोप के लिए. इस कॉन्फ़िगरेशन की वजह से, आपको टेस्ट शेड्यूलर को मैन्युअल तरीके से सिंक करना पड़ सकता है.
@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 एपीआई, अपने 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() } }