अपने ऐप्लिकेशन में Paging लाइब्रेरी को लागू करने के साथ-साथ, टेस्टिंग की मज़बूत रणनीति का इस्तेमाल करना चाहिए. आपको डेटा लोड करने वाले कॉम्पोनेंट की जांच करनी चाहिए. जैसे,
PagingSource और
RemoteMediator
यह पक्का करने के लिए कि वे उम्मीद के मुताबिक काम कर रहे हैं. आपको एंड-टू-एंड टेस्ट भी लिखने चाहिए, ताकि यह पुष्टि की जा सके कि Paging को लागू करने के दौरान इस्तेमाल किए गए सभी कॉम्पोनेंट, एक साथ सही तरीके से काम कर रहे हैं. साथ ही, यह भी पुष्टि की जा सके कि इससे कोई अनचाहा असर नहीं पड़ रहा है.
इस गाइड में, आपके ऐप्लिकेशन की अलग-अलग आर्किटेक्चर लेयर में Paging लाइब्रेरी को टेस्ट करने का तरीका बताया गया है. साथ ही, इसमें Paging लाइब्रेरी को पूरी तरह से लागू करने के लिए, एंड-टू-एंड टेस्ट लिखने का तरीका भी बताया गया है.
यूज़र इंटरफ़ेस (यूआई) लेयर की जांच करना
Compose, collectAsLazyPagingItems के ज़रिए पेजिंग डेटा का इस्तेमाल करता है. इसलिए, यूज़र इंटरफ़ेस (यूआई) लेयर के टेस्ट, पूरी तरह से ViewModel से जनरेट होने वाले Flow<PagingData<Value>> पर फ़ोकस कर सकते हैं. अगर आपको यह पुष्टि करने के लिए टेस्ट लिखने हैं कि यूज़र इंटरफ़ेस (यूआई) में मौजूद डेटा आपकी उम्मीद के मुताबिक है, तो paging-testing डिपेंडेंसी शामिल करें. इसमें Flow<PagingData<Value>> पर asSnapshot एक्सटेंशन शामिल होता है. यह अपने लैम्डा रिसीवर में एपीआई उपलब्ध कराता है. इनकी मदद से, स्क्रोलिंग इंटरैक्शन को मॉक किया जा सकता है. यह स्क्रोलिंग इंटरैक्शन से जनरेट किया गया स्टैंडर्ड List<Value> दिखाता है.
इससे यह पुष्टि की जा सकती है कि पेज किए जा रहे डेटा में, उन इंटरैक्शन से जनरेट किए गए ज़रूरी एलिमेंट शामिल हैं. इसे इस स्निपेट में दिखाया गया है:
fun test_items_contain_one_to_ten() = runTest {
// Get the Flow of PagingData from the ViewModel under test
val items: Flow<PagingData<String>> = viewModel.items
val itemsSnapshot: List<String> = items.asSnapshot {
// Scroll to the 50th item in the list. This will also suspend till
// the prefetch requirement is met if there's one.
// It also suspends until all loading is complete.
scrollTo(index = 50)
}
// With the asSnapshot complete, you can now verify that the snapshot
// has the expected values
assertEquals(
expected = (0..50).map(Int::toString),
actual = itemsSnapshot
)
}
इसके अलावा, नीचे दिए गए स्निपेट में दिखाए गए तरीके से, किसी शर्त के पूरा होने तक स्क्रोल किया जा सकता है:
fun test_footer_is_visible() = runTest {
// Get the Flow of PagingData from the ViewModel under test
val items: Flow<PagingData<String>> = viewModel.items
val itemsSnapshot: List<String> = items.asSnapshot {
// Scroll till the footer is visible
appendScrollWhile { item: String -> item != "Footer" }
}
बदलावों की जांच करना
आपको यूनिट टेस्ट भी लिखने चाहिए. इनमें, PagingData स्ट्रीम में किए गए सभी बदलावों को शामिल किया जाना चाहिए. asPagingSourceFactory एक्सटेंशन का इस्तेमाल करें. यह एक्सटेंशन, इन डेटा टाइप के लिए उपलब्ध है:
List<Value>.Flow<List<Value>>.
आपको जिस एक्सटेंशन का इस्तेमाल करना है वह इस बात पर निर्भर करता है कि आपको किस चीज़ की जांच करनी है. इस्तेमाल करें:
List<Value>.asPagingSourceFactory(): अगर आपको डेटा परmap()औरinsertSeparators()जैसे स्टैटिक ट्रांसफ़ॉर्मेशन की जांच करनी है.Flow<List<Value>>.asPagingSourceFactory(): अगर आपको यह टेस्ट करना है कि डेटा में किए गए अपडेट, जैसे कि बैकिंग डेटा सोर्स में लिखना, आपकी पेजिंग पाइपलाइन पर कैसे असर डालता है.
इनमें से किसी भी एक्सटेंशन का इस्तेमाल करने के लिए, इस पैटर्न का पालन करें:
- अपनी ज़रूरतों के हिसाब से सही एक्सटेंशन का इस्तेमाल करके,
PagingSourceFactoryबनाएं. Repositoryके लिए, वापस भेजे गएPagingSourceFactoryका इस्तेमाल नकली तौर पर करें.- उस
Repositoryको अपनेViewModelपर पास करें.
इसके बाद, ViewModel की जांच की जा सकती है. इसके बारे में पिछले सेक्शन में बताया गया है.
इन बातों का ध्यान रखें ViewModel:
class MyViewModel(
myRepository: myRepository
) {
val items = Pager(
config: PagingConfig,
initialKey = null,
pagingSourceFactory = { myRepository.pagingSource() }
)
.flow
.map { pagingData ->
pagingData.insertSeparators<String, String> { before, _ ->
when {
// Add a dashed String separator if the prior item is a multiple of 10
before.last() == '0' -> "---------"
// Return null to avoid adding a separator between two items.
else -> null
}
}
}
MyViewModel में ट्रांसफ़ॉर्मेशन की जांच करने के लिए, MyRepository का एक फ़र्ज़ी इंस्टेंस उपलब्ध कराएं. यह इंस्टेंस, स्टैटिक List को डेलिगेट करता है. यह List, ट्रांसफ़ॉर्म किए जाने वाले डेटा को दिखाता है. इसे यहां दिए गए स्निपेट में दिखाया गया है:
class FakeMyRepository() : MyRepository {
private val items = (0..100).map(Any::toString)
private val pagingSourceFactory = items.asPagingSourceFactory()
// Expose as a function so a new PagingSource instance is
// created each time it is called by the Pager
fun pagingSource() = pagingSourceFactory()
}
इसके बाद, सेपरेटर लॉजिक के लिए एक टेस्ट लिखा जा सकता है. जैसे, यहां दिए गए स्निपेट में दिखाया गया है:
fun test_separators_are_added_every_10_items() = runTest {
// Create your ViewModel
val viewModel = MyViewModel(
myRepository = FakeMyRepository()
)
// Get the Flow of PagingData from the ViewModel with the separator transformations applied
val items: Flow<PagingData<String>> = viewModel.items
val snapshot: List<String> = items.asSnapshot()
// With the asSnapshot complete, you can now verify that the snapshot
// has the expected separators.
}
डेटा लेयर के टेस्ट
अपने डेटा लेयर में मौजूद कॉम्पोनेंट के लिए यूनिट टेस्ट लिखें. इससे यह पक्का किया जा सकेगा कि वे आपके डेटा सोर्स से डेटा को सही तरीके से लोड करते हैं. डिपेंडेंसी के नकली वर्शन उपलब्ध कराएं, ताकि यह पुष्टि की जा सके कि टेस्ट किए जा रहे कॉम्पोनेंट, आइसोलेशन में सही तरीके से काम करते हैं. रिपॉज़िटरी लेयर में, आपको इन मुख्य कॉम्पोनेंट की जांच करनी होगी: PagingSource और RemoteMediator.
PagingSource टेस्ट
PagingSource को लागू करने के लिए यूनिट टेस्ट में, PagingSource इंस्टेंस सेट अप करना और TestPager की मदद से उससे डेटा लोड करना शामिल है.
जांच के लिए PagingSource इंस्टेंस सेट अप करने के लिए, कंस्ट्रक्टर को नकली डेटा दें. इससे आपको अपनी जांच में मौजूद डेटा को कंट्रोल करने की सुविधा मिलती है.
यहां दिए गए उदाहरण में, RedditApi पैरामीटर एक Retrofit इंटरफ़ेस है. यह सर्वर के अनुरोधों और जवाब की क्लास तय करता है.
नकली वर्शन, इंटरफ़ेस को लागू कर सकता है, किसी भी ज़रूरी फ़ंक्शन को बदल सकता है, और नकली ऑब्जेक्ट को कॉन्फ़िगर करने के लिए आसान तरीके उपलब्ध करा सकता है. इससे यह तय किया जा सकता है कि नकली ऑब्जेक्ट, टेस्ट में कैसे काम करेगा.
फ़ेक ऑब्जेक्ट सेट अप करने के बाद, डिपेंडेंसी सेट अप करें और टेस्ट में PagingSource ऑब्जेक्ट को शुरू करें. यहां दिए गए उदाहरण में, टेस्ट पोस्ट की सूची के साथ FakeRedditApi ऑब्जेक्ट को शुरू करने और RedditPagingSource इंस्टेंस की जांच करने का तरीका दिखाया गया है:
class SubredditPagingSourceTest {
private val mockPosts = listOf(
postFactory.createRedditPost(DEFAULT_SUBREDDIT),
postFactory.createRedditPost(DEFAULT_SUBREDDIT),
postFactory.createRedditPost(DEFAULT_SUBREDDIT)
)
private val fakeApi = FakeRedditApi().apply {
mockPosts.forEach { post -> addPost(post) }
}
@Test
fun loadReturnsPageWhenOnSuccessfulLoadOfItemKeyedData() = runTest {
val pagingSource = RedditPagingSource(
fakeApi,
DEFAULT_SUBREDDIT
)
val pager = TestPager(CONFIG, pagingSource)
val result = pager.refresh() as LoadResult.Page
// Write assertions against the loaded data
assertThat(result.data)
.containsExactlyElementsIn(mockPosts)
.inOrder()
}
}
TestPager की मदद से, ये काम भी किए जा सकते हैं:
- अपने
PagingSourceसे लगातार लोड होने वाले डेटा की जांच करें:
@Test
fun test_consecutive_loads() = runTest {
val page = with(pager) {
refresh()
append()
append()
} as LoadResult.Page
assertThat(page.data)
.containsExactlyElementsIn(testPosts)
.inOrder()
}
- अपने
PagingSourceमें गड़बड़ी के उदाहरणों की जांच करें:
@Test
fun refresh_returnError() {
val pagingSource = RedditPagingSource(
fakeApi,
DEFAULT_SUBREDDIT
)
// Configure your fake to return errors
fakeApi.setReturnsError()
val pager = TestPager(CONFIG, source)
runTest {
source.errorNextLoad = true
val result = pager.refresh()
assertTrue(result is LoadResult.Error)
val page = pager.getLastLoadedPage()
assertThat(page).isNull()
}
}
RemoteMediator टेस्ट
RemoteMediator यूनिट टेस्ट का मकसद यह पुष्टि करना है कि RemoteMediator फ़ंक्शन सही MediatorResult दिखाता है.load()
डेटाबेस में डेटा डालने जैसे साइड इफ़ेक्ट की जांच करने के लिए, इंटिग्रेशन टेस्ट ज़्यादा सही होते हैं.
पहला चरण यह तय करना है कि आपके RemoteMediator
लागू करने के लिए किन डिपेंडेंसी की ज़रूरत है. यहां RemoteMediator को लागू करने का एक उदाहरण दिया गया है. इसके लिए, रूम डेटाबेस, रेट्रोफ़िट इंटरफ़ेस, और खोज स्ट्रिंग की ज़रूरत होती है:
@OptIn(ExperimentalPagingApi::class)
class PageKeyedRemoteMediator(
private val db: RedditDb,
private val redditApi: RedditApi,
private val subredditName: String
) : RemoteMediator<Int, RedditPost>() {
...
}
PagingSource टेस्ट सेक्शन में दिखाए गए तरीके से, रेट्रोफ़िट इंटरफ़ेस और खोज स्ट्रिंग दी जा सकती है. रूम डेटाबेस का मॉक वर्शन उपलब्ध कराना बहुत मुश्किल होता है. इसलिए, पूरे मॉक वर्शन के बजाय डेटाबेस का इन-मेमोरी वर्शन उपलब्ध कराना आसान हो सकता है. Room डेटाबेस बनाने के लिए, Context ऑब्जेक्ट की ज़रूरत होती है. इसलिए, आपको इस RemoteMediator टेस्ट को androidTest डायरेक्ट्री में रखना होगा. साथ ही, इसे AndroidJUnit4 टेस्ट रनर के साथ एक्ज़ीक्यूट करना होगा, ताकि इसके पास टेस्ट ऐप्लिकेशन के कॉन्टेक्स्ट का ऐक्सेस हो. इंस्ट्रुमेंटेड टेस्ट के बारे में ज़्यादा जानने के लिए, इंस्ट्रुमेंटेड यूनिट टेस्ट बनाएं लेख पढ़ें.
टेस्ट फ़ंक्शन के बीच स्टेट लीक न हो, इसके लिए टीयर-डाउन फ़ंक्शन तय करें. इससे यह पक्का होता है कि टेस्ट रन के बीच नतीजे एक जैसे हों.
@ExperimentalPagingApi
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(AndroidJUnit4::class)
class PageKeyedRemoteMediatorTest {
private val postFactory = PostFactory()
private val mockPosts = listOf(
postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT),
postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT),
postFactory.createRedditPost(SubRedditViewModel.DEFAULT_SUBREDDIT)
)
private val mockApi = mockRedditApi()
private val mockDb = RedditDb.create(
ApplicationProvider.getApplicationContext(),
useInMemory = true
)
@After
fun tearDown() {
mockDb.clearAllTables()
// Clear out failure message to default to the successful response.
mockApi.failureMsg = null
// Clear out posts after each test run.
mockApi.clearPosts()
}
}
अगला चरण, load() फ़ंक्शन को टेस्ट करना है. इस उदाहरण में, टेस्ट करने के लिए तीन केस दिए गए हैं:
- पहला मामला तब होता है, जब
mockApiमान्य डेटा दिखाता है.load()फ़ंक्शन कोMediatorResult.Successदिखाना चाहिए औरendOfPaginationReachedप्रॉपर्टी कोfalseहोना चाहिए. - दूसरा केस तब होता है, जब
mockApiसे सही जवाब मिलता है, लेकिन मिले हुए डेटा में कोई वैल्यू नहीं होती.load()फ़ंक्शन कोMediatorResult.Successवैल्यू दिखानी चाहिए औरendOfPaginationReachedप्रॉपर्टी कोtrueवैल्यू दिखानी चाहिए. - तीसरा मामला तब होता है, जब डेटा फ़ेच करते समय
mockApiकोई अपवाद दिखाता है.load()फ़ंक्शन कोMediatorResult.Errorदिखाना चाहिए.
पहले मामले की जांच करने के लिए, यह तरीका अपनाएं:
- डेटा वापस पाने के लिए, पोस्ट डेटा के साथ
mockApiसेट अप करें. RemoteMediatorऑब्जेक्ट को शुरू करें.load()फ़ंक्शन को आज़माएं.
@Test
fun refreshLoadReturnsSuccessResultWhenMoreDataIsPresent() = runTest {
// Add mock results for the API to return.
mockPosts.forEach { post -> mockApi.addPost(post) }
val remoteMediator = PageKeyedRemoteMediator(
mockDb,
mockApi,
SubRedditViewModel.DEFAULT_SUBREDDIT
)
val pagingState = PagingState<Int, RedditPost>(
listOf(),
null,
PagingConfig(10),
10
)
val result = remoteMediator.load(LoadType.REFRESH, pagingState)
assertTrue { result is MediatorResult.Success }
assertFalse { (result as MediatorResult.Success).endOfPaginationReached }
}
दूसरे टेस्ट के लिए, mockApi को कोई नतीजा नहीं दिखाना होगा. हर टेस्ट रन के बाद, mockApi से डेटा मिटा दिया जाता है. इसलिए, यह डिफ़ॉल्ट रूप से खाली नतीजा दिखाएगा.
@Test
fun refreshLoadSuccessAndEndOfPaginationWhenNoMoreData() = runTest {
// To test endOfPaginationReached, don't set up the mockApi to return post
// data here.
val remoteMediator = PageKeyedRemoteMediator(
mockDb,
mockApi,
SubRedditViewModel.DEFAULT_SUBREDDIT
)
val pagingState = PagingState<Int, RedditPost>(
listOf(),
null,
PagingConfig(10),
10
)
val result = remoteMediator.load(LoadType.REFRESH, pagingState)
assertTrue { result is MediatorResult.Success }
assertTrue { (result as MediatorResult.Success).endOfPaginationReached }
}
आखिरी टेस्ट के लिए, mockApi को एक अपवाद जनरेट करना होगा, ताकि टेस्ट यह पुष्टि कर सके कि load() फ़ंक्शन, MediatorResult.Error को सही तरीके से दिखाता है.
@Test
fun refreshLoadReturnsErrorResultWhenErrorOccurs() = runTest {
// Set up failure message to throw exception from the mock API.
mockApi.failureMsg = "Throw test failure"
val remoteMediator = PageKeyedRemoteMediator(
mockDb,
mockApi,
SubRedditViewModel.DEFAULT_SUBREDDIT
)
val pagingState = PagingState<Int, RedditPost>(
listOf(),
null,
PagingConfig(10),
10
)
val result = remoteMediator.load(LoadType.REFRESH, pagingState)
assertTrue {result is MediatorResult.Error }
}
शुरू से आखिर तक के टेस्ट
यूनिट टेस्ट से यह पक्का किया जाता है कि अलग-अलग पेजिंग कॉम्पोनेंट, आइसोलेशन में काम करते हैं. हालांकि, एंड-टू-एंड टेस्ट से यह पक्का किया जाता है कि ऐप्लिकेशन पूरी तरह से काम करता है. इन टेस्ट से यह पुष्टि करने में मदद मिलती है कि आपका डेटा लेयर (PagingSource या RemoteMediator), ViewModel, और Compose UI, बिना किसी अनचाहे साइड इफ़ेक्ट के आसानी से इंटिग्रेट हो गया है. जांच के लिए अब भी कुछ मॉक डिपेंडेंसी की ज़रूरत होगी. हालांकि, आम तौर पर ये आपके ऐप्लिकेशन के ज़्यादातर कोड को कवर करेंगी.
इस सेक्शन में दिए गए उदाहरण में, मॉक एपीआई डिपेंडेंसी का इस्तेमाल किया गया है, ताकि टेस्ट में नेटवर्क का इस्तेमाल न करना पड़े. मॉक एपीआई को टेस्ट डेटा का एक जैसा सेट दिखाने के लिए कॉन्फ़िगर किया जाता है. इससे टेस्ट को बार-बार दोहराया जा सकता है. एंड-टू-एंड टेस्ट के लिए, आम तौर पर अपने असली नेटवर्क एपीआई को नकली एपीआई से बदल दिया जाता है. हालांकि, Paging लाइब्रेरी को अब भी डेटा फ़ेच करने और लोकल डेटाबेस में कैश मेमोरी सेव करने की सुविधा (अगर RemoteMediator का इस्तेमाल किया जा रहा है) को मैनेज करने की अनुमति दी जाती है, ताकि आपके टेस्ट की विश्वसनीयता बनी रहे.
अपने कोड को इस तरह से लिखो कि आप अपनी डिपेंडेंसी के मॉक वर्शन को आसानी से बदल सकें. यहां दिए गए उदाहरण में, सर्विस लोकेटर के बुनियादी तौर पर लागू करने का इस्तेमाल किया गया है. साथ ही, मॉक एपीआई के साथ एक टेस्ट सेट अप किया गया है. इससे यह पुष्टि की जा सकेगी कि Compose स्क्रीन, पेज में बंटे डेटा को ठीक से इस्तेमाल करती है और उसे दिखाती है. बड़े ऐप्लिकेशन में, Hilt जैसी डिपेंडेंसी इंजेक्शन लाइब्रेरी का इस्तेमाल करके, ज़्यादा जटिल डिपेंडेंसी ग्राफ़ मैनेज किए जा सकते हैं.
टेस्ट स्ट्रक्चर सेट अप करने के बाद, अगला चरण यह पुष्टि करना है कि Pager लागू करने से मिला डेटा सही है. एक टेस्ट से यह पुष्टि होनी चाहिए कि स्क्रीन के पहली बार लोड होने पर, Compose UI में सही आइटम दिख रहे हैं. वहीं, दूसरे टेस्ट से यह पुष्टि होनी चाहिए कि यूज़र इंटरैक्शन के आधार पर, यूज़र इंटरफ़ेस (यूआई) में सही तरीके से अतिरिक्त डेटा लोड हो रहा है.
यहां दिए गए उदाहरण में, टेस्ट यह पुष्टि करता है कि यूज़र इंटरफ़ेस (यूआई) में पेज के हिसाब से डेटा दिख रहा है या नहीं.
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.assertDoesNotExist
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performTextClearance
import androidx.compose.ui.test.performTextInput
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class RedditScreenTest {
@get:Rule
val composeTestRule = createComposeRule()
private val postFactory = PostFactory()
private val mockApi = MockRedditApi()
@Before
fun setup() {
// Pre-populate the mock API with test data for the default subreddit
mockApi.addPost(postFactory.createRedditPost(subreddit = "androiddev", title = "Jetpack Compose Paging"))
// Swap your real dependency injection module/Service Locator with the mock API
ServiceLocator.swap(
object : DefaultServiceLocator(useInMemoryDb = true) {
override fun getRedditApi(): RedditApi = mockApi
}
)
}
@Test
fun loadsTheDefaultResults() = runTest {
// 1. Set the Compose UI content
composeTestRule.setContent {
MyTheme {
// Assume that this composable uses `collectAsLazyPagingItems()` internally
RedditScreen(initialSubreddit = "androiddev")
}
}
// 2. Wait for the asynchronous Paging loads to complete
composeTestRule.waitUntilExactlyOneExists(
matcher = hasText("Jetpack Compose Paging"),
timeoutMillis = 5000
)
// 3. Assert that the loaded paged items are displayed correctly on screen
composeTestRule.onNodeWithText("Jetpack Compose Paging").assertIsDisplayed()
}
@Test
fun loadsNewDataBasedOnUserInput() = runTest {
// Add data for a different subreddit to the mock API
mockApi.addPost(postFactory.createRedditPost(subreddit = "compose", title = "Compose Testing"))
composeTestRule.setContent {
MyTheme {
RedditScreen(initialSubreddit = "androiddev")
}
}
// Wait for the initial load to finish
composeTestRule.waitUntilExactlyOneExists(hasText("Jetpack Compose Paging"))
// Simulate user entering a new subreddit in a text field and clicking search
composeTestRule.onNodeWithTag("SubredditInput").performTextClearance()
composeTestRule.onNodeWithTag("SubredditInput").performTextInput("compose")
composeTestRule.onNodeWithTag("SearchButton").performClick()
// Wait for the new paged data to load
composeTestRule.waitUntilExactlyOneExists(
matcher = hasText("Compose Testing"),
timeoutMillis = 5000
)
// Assert the old data is gone and the new data is displayed
composeTestRule.onNodeWithText("Jetpack Compose Paging").assertDoesNotExist()
composeTestRule.onNodeWithText("Compose Testing").assertIsDisplayed()
}
}
Flow<PagingData> डेटा को एसिंक्रोनस तरीके से लोड करता है. इसलिए, आपको Paging लाइब्रेरी को शुरुआती डेटा लोड करने और उसे collectAsLazyPagingItems को भेजने का समय देना होगा. इसके बाद ही, पुष्टि की जा सकती है. इसके लिए, composeTestRule.waitUntil या waitUntilExactlyOneExists का इस्तेमाल करें. जैसा कि ऊपर दिए गए उदाहरण में दिखाया गया है.
डेटा लोड होने के बाद, onNodeWithText का इस्तेमाल करके, Compose के सिमैंटिक ट्री के ख़िलाफ़ सीधे तौर पर पुष्टि की जा सकती है. इससे यह पुष्टि की जा सकती है कि आइटम, आपके LazyColumn में रेंडर किए गए हैं या नहीं.
अन्य संसाधन
कॉन्टेंट देखता है
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक का टेक्स्ट दिखता है
- नेटवर्क और डेटाबेस से पेज
- Paging 3 पर माइग्रेट करना
- पेज में बंटे डेटा को लोड करना और दिखाना