نحوه تست Proto DataStore
در مقاله قبلی ، توضیح دادم که چگونه می توانید از Proto DataStore در برنامه خود استفاده کنید. من آن مقاله را به عنوان بخشی از تجربه خود در استفاده از Proto DataStore در یکی از برنامه هایم نوشتم.
به دنبال آن، میخواستم ببینم نوشتن تستهایی برای Proto DataStore در آن برنامه با استفاده از دانشی که به دست آوردم چگونه است.
جستجوی آنلاین برای راهنمایی کمک چندانی نکرد، پس فکر کردم دانش خود را برای کسانی که ممکن است به دنبال آن باشند به اشتراک بگذارم. در بدترین حالت، این برای فرزندان من خواهد بود.
در جستجوی خود، این مقاله را پیدا کردم، اما این مقاله بیشتر بر روی آزمایش Preferences DataStore و نه Proto DataStore تمرکز دارد. بیان می کند که:
با این حال، به خاطر داشته باشید که می توانید از این ماده برای راه اندازی تست Proto DataStore استفاده کنید، زیرا بسیار شبیه به Preferences است.
اما با دنبال کردن آن، متوجه شدم که علاوه بر وابستگی ها، شباهت های زیادی در اینجا وجود ندارد و شما باید منطق جداگانه ای را برای آزمایش Proto DataStore خود معرفی کنید.
تنظیم چیزها
در فایل build.gradle برنامه خود، وابستگی های زیر را اضافه کنید:
dependencies { ///..... androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" }
$compose_version
متغیری است که در فایل build.gradle سطح پروژه خود تعریف کرده اید.
سپس، به پوشه androidTest
خود بروید و یک فایل جدید ایجاد کنید. معمولاً، شما یک کلاس مخزن دارید که با Proto DataStore شما تعامل دارد، پس می توانید نام این فایل را YourRepositoryClassNameTest بگذارید. ما از نام MyRepositoryTest
استفاده خواهیم کرد.
قبل از اینکه به آزمایش خود Proto DataStore بپردازیم، باید آن را نمونه سازی کنیم. اگر برای یافتن هر گونه سندی در این مورد به اینترنت بروید، به نوعی پراکنده است.
نمونه سازی Proto DataStore با زمینه جهانی مانند آن استفاده می شود (زمانی که در یک سناریوی آزمایشی استفاده نمی شود):
private val Context.myDataStore: DataStore<MyItem> by dataStore( fileName = DATA_STORE_FILE_NAME, serializer = MyItemSerializer )
خوب، شما نمی توانید این کار را در یک کلاس آزمایشی انجام دهید، زیرا در حالی که می توانید کد بالا را کپی پیست کنید، نمی توانید به شی DataStore دسترسی پیدا کنید . می توانید زمینه برنامه را به صورت زیر دریافت کنید:
ApplicationProvider.getApplicationContext()
اما شی myDataStore
ما از طریق آن در دسترس نخواهد بود.
پس چه می توانیم بکنیم؟
در مقاله لینک شده در بالا، مثالی از نحوه ایجاد Preference DataStore با استفاده از روش PreferenceDataStoreFactory.create وجود دارد.
fun create( corruptionHandler: ReplaceFileCorruptionHandler<Preferences>? = null, migrations: List<DataMigration<Preferences>> = listOf(), scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()), produceFile: () -> File): DataStore<Preferences>
اما از آنجایی که ما از Preference DataStore استفاده نمی کنیم، این برای ما کار نخواهد کرد. چیزی که کار خواهد کرد استفاده از روش DataStoreFactory.create مانند این است:
fun <T : Any?> create( serializer: Serializer<T>, corruptionHandler: ReplaceFileCorruptionHandler<T>? = null, migrations: List<DataMigration<T>> = listOf(), scope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob()), produceFile: () -> File): DataStore<T>
چندین آرگومان برای این متد وجود دارد (و برخی دارای مقادیر پیشفرض هستند)، اما نیازی نیست که همه آنها را وارد کنیم.
کلاس سریال ساز ما
یک روش لامبدا برای ایجاد فایل برای Proto DataStore ما
dataStore = DataStoreFactory.create( produceFile = { testContext.dataStoreFile(TEST_DATA_STORE_FILE_NAME) }, serializer = MyItemSerializer )
ما testContext
با استفاده از:
private val testContext: Context = ApplicationProvider.getApplicationContext()
نحوه تست DataStore
پس از ایجاد Proto DataStore خود با موفقیت، میتوانیم به نوشتن آزمایشهایی برای آن بپردازیم. به خاطر داشته باشید که شما یک کلاس مخزن دارید که نمونه Proto DataStore را به عنوان یک وابستگی دریافت می کند، پس پس از ایجاد Proto DataStore، باید یک نمونه از کلاس مخزن خود ایجاد کنیم.
private val repository = MyRepository(datastore)
ابتدا، بیایید یک آزمایش برای تحلیل وضعیت اولیه Proto DataStore خود ایجاد کنیم. Proto DataStore خود جریانی را نشان می دهد که ما می توانیم از آن استفاده کنیم.
@OptIn(ExperimentalCoroutinesApi::class) @Test fun repository_testFetchInitialState() { runTest { testScope.launch { val dataStoreObject = repository.myFlow.first() // Insert here whatever we want to assert from our // Proto DataStore. IE a flag whose initial value is false assert(dataStoreObject.myFlag == false) } } }
☝️ ممکن است قبلا متوجه این موضوع شده باشید، اما ما در اینجا از یک حاشیه نویسی OptIn استفاده می کنیم. این به این دلیل است که (در حال حاضر) API هایی که ما استفاده می کنیم آزمایشی هستند و باید هنگام استفاده از آنها علامت گذاری شوند.
از آنجایی که ما به جریان DataStore
خود دسترسی داریم، باید آن را در testScope
خود قرار دهیم. TestScope
با انجام زیر ایجاد می شود:
@OptIn(ExperimentalCoroutinesApi::class) private val dispatcher = TestCoroutineDispatcher() @OptIn(ExperimentalCoroutinesApi::class) private val testScope = TestCoroutineScope(dispatcher)
آن را اجرا کنید و از اولین تست Proto DataStore خود لذت ببرید.
برای حدود دو ثانیه جالب بود.
بیایید کاری معنادارتر انجام دهیم.
تصور کنید Proto DataStore ما فهرستی از اشیاء را در داخل خود دارد و میخواهیم وضعیت آن را هنگامی که یک آیتم را به آن اضافه میکنیم، آزمایش کنیم.
@OptIn(ExperimentalCoroutinesApi::class) @Test fun repository_testAdditionOfItem() { runTest { testScope.launch { //1 val item: MyItem = MyItem.newBuilder().setItemId(UUID.randomUUID().toString()) .setItemDescription(TEST_ITEM_DESCRIPTION).build() //2 repository.updateItem(item) //3 val items = repository.myFlow.first().itemsList assert(items.size == 1) //4 assert(items[0].itemDescription.equals(TEST_ITEM_DESCRIPTION)) } } }
ما یک آیتم آزمایشی را با استفاده از API در معرض نمایش از protobuff ایجاد می کنیم
ما این مورد را با استفاده از روشی که در کلاس MyRepository در معرض دید قرار داده ایم به Proto DataStore اضافه می کنیم
ما فهرست ی از موارد را از جریانی که Proto DataStore در معرض دید قرار می دهد، می گیریم
ما مطمئن می شویم که موردی که در Proto DataStore یافت می شود با آیتمی که قبلا ایجاد کرده بودیم مطابقت داشته باشد
DataStore شما نشتی در آن دارد
اگر سعی کنید تست های بالا را یکباره اجرا کنید، به زودی در زمان اجرا با یک خطا مواجه خواهید شد:
چندین DataStore برای یک فایل فعال وجود دارد: /data/user/0/com.example.app/files/datastore/dataStore_filename.pb. یا باید DataStore خود را به صورت تکی نگهداری کنید یا تأیید کنید که هیچ دو DataStore در یک فایل فعال وجود ندارد (با تأیید لغو دامنه).
خب این مشکل داره ما فقط یک نمونه DataStore در کلاس آزمایشی خود ایجاد کردیم.
اینجا چه خبر است؟
از آنجایی که ما از ویژگی delegate برای ایجاد DataStore خود (به معنی Context.datastore) استفاده نمی کنیم، مطمئن نیستیم که شی DataStore ما هر زمان که به آن دسترسی پیدا می کنیم، تکی است.
برای دور زدن این سناریو، متوجه شده ام که یک روش حذف و ایجاد مجدد DataStore برای هر مورد آزمایشی است. برای حذف DataStore، می توانیم این کار را انجام دهیم:
@After fun cleanup() { File(testContext.filesDir, "datastore").deleteRecursively() }
و قبل از هر آزمایش، آن را دوباره ایجاد می کنیم:
@Before fun setup() { dataStore = DataStoreFactory.create( produceFile = { testContext.dataStoreFile(TEST_DATA_STORE_FILE_NAME) }, serializer = MyItemSerializer ) }
برای مشاهده نمونه کامل می توانید به اینجا بروید.
در این مقاله، من میخواستم طرح کلی نحوه تست Proto DataStore را نشان دهم.
در حالی که من دو مورد آزمایشی را تحلیل کردم، بسته به DataStore شما و انواعی که در آنجا پیکربندی کردهاید، ممکن است موارد و سناریوهای تست بیشتری برای نوشتن وجود داشته باشد. بلوک های ساختمان وجود دارد، شما فقط باید آن را با نیازهای خود تطبیق دهید.
ارسال نظر