از تست دوبل در اندروید استفاده کنید

هنگام طراحی استراتژی تست برای یک عنصر یا سیستم، سه جنبه تست مرتبط وجود دارد:

  • محدوده : تست چه مقدار از کد را لمس می کند؟ آزمایش‌ها می‌توانند یک روش واحد، کل برنامه یا جایی در این بین را تأیید کنند. محدوده آزمایش شده در حال آزمایش است و معمولاً از آن به عنوان موضوع تحت آزمایش یاد می شود، البته سیستم در حال آزمایش یا واحد در حال آزمایش نیز نامیده می شود.
  • سرعت : تست با چه سرعتی اجرا می شود؟ سرعت تست می تواند از میلی ثانیه تا چند دقیقه متفاوت باشد.
  • وفاداری : آزمون چقدر «دنیای واقعی» است؟ به عنوان مثال، اگر بخشی از کدی که در حال آزمایش آن هستید نیاز به درخواست شبکه داشته باشد، آیا کد آزمایشی واقعاً این درخواست شبکه را انجام می دهد یا نتیجه را جعلی می کند؟ اگر آزمون واقعاً با شبکه صحبت می کند، به این معنی است که وفاداری بالاتری دارد. معاوضه این است که اجرای آزمایش ممکن است بیشتر طول بکشد، در صورت قطع شدن شبکه ممکن است منجر به خطا شود یا استفاده از آن پرهزینه باشد.

ببینید چه چیزی را باید آزمایش کنید تا یاد بگیرید که چگونه استراتژی تست خود را تعریف کنید.

انزوا و وابستگی ها

وقتی یک عنصر یا سیستمی از عناصر را آزمایش می کنید، این کار را به صورت مجزا انجام می دهید. برای مثال، برای آزمایش ViewModel، نیازی به راه‌اندازی شبیه‌ساز و راه‌اندازی یک رابط کاربری ندارید، زیرا به چارچوب اندروید بستگی ندارد (یا نباید).

با این حال، موضوع مورد آزمایش ممکن است برای کارکرد آن به دیگران بستگی داشته باشد. به عنوان مثال، یک ViewModel ممکن است به یک مخزن داده برای کار بستگی داشته باشد.

زمانی که نیاز به ایجاد وابستگی به موضوع مورد آزمایش دارید، یک روش معمول ایجاد یک تست دوبل (یا شیء آزمایشی ) است. دوبل های تست اشیایی هستند که به عنوان اجزای برنامه شما به نظر می رسند و عمل می کنند اما در آزمایش شما برای ارائه یک رفتار یا داده خاص ایجاد شده اند. مزایای اصلی این است که آنها تست های شما را سریع تر و ساده تر می کنند.

انواع تست دوبل

انواع مختلف تست دوبل وجود دارد:

جعلی یک تست دوبل که دارای یک پیاده سازی "کار" کلاس است، اما به گونه ای پیاده سازی شده است که برای تست ها خوب است اما برای تولید نامناسب است.

مثال: یک پایگاه داده در حافظه.

تقلبی ها نیازی به چارچوب تمسخر آمیز ندارند و سبک وزن هستند. آنها ترجیح داده می شوند.

مسخره کردن یک تست دوتایی که نحوه برنامه ریزی شما برای رفتار کردن و انتظاراتی در مورد تعاملاتش دارد. اگر تقلب‌ها با الزاماتی که شما تعریف کرده‌اید مطابقت نداشته باشد، در آزمون‌ها شکست خواهند خورد. برای دستیابی به همه اینها، ماک ها معمولاً با یک چارچوب تمسخر آمیز ساخته می شوند.

مثال: بررسی کنید که یک متد در پایگاه داده دقیقا یک بار فراخوانی شده باشد.

خرد یک تست دوتایی که نحوه برنامه‌ریزی شما را برای رفتار برنامه‌ریزی می‌کند، اما در مورد تعاملات آن انتظاری ندارد. معمولا با یک چارچوب تمسخر آمیز ایجاد می شود. تقلبی ها به دلیل سادگی به خرد ترجیح داده می شوند.
ساختگی یک تست دوتایی که در اطراف ارسال می شود اما استفاده نمی شود، مثلاً اگر فقط باید آن را به عنوان یک پارامتر ارائه کنید.

مثال: یک تابع خالی به عنوان یک کلیک برگشتی ارسال می شود.

جاسوس یک لفاف بر روی یک شی واقعی که برخی از اطلاعات اضافی را نیز مانند مسخره کردن، ردیابی می کند. معمولاً برای افزودن پیچیدگی از آنها اجتناب می شود. بنابراین جعلی یا مسخره بر جاسوسان ترجیح داده می شود.
سایه جعلی مورد استفاده در Robolectric.

مثال استفاده از جعلی

فرض کنید که می خواهید یک ViewModel را واحد آزمایش کنید که به رابطی به نام UserRepository وابسته است و نام اولین کاربر را در معرض یک UI قرار می دهد. شما می توانید با پیاده سازی رابط و برگرداندن داده های شناخته شده، یک تست جعلی ایجاد کنید.

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

این UserRepository جعلی نیازی به وابستگی به منابع داده محلی و راه دوری ندارد که نسخه تولیدی از آنها استفاده می کند. فایل در مجموعه منبع آزمایشی زندگی می کند و با برنامه تولید ارسال نمی شود.

یک وابستگی جعلی می تواند داده های شناخته شده را بدون وابستگی به منابع داده از راه دور بازگرداند
شکل 1 : یک وابستگی جعلی در آزمون واحد.

آزمایش زیر تأیید می کند که ViewModel به درستی اولین نام کاربری را در معرض دید قرار می دهد.

@Test
fun viewModelA_loadsUsers_showsFirstUser() {
    // Given a VM using fake data
    val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init

    // Verify that the exposed data is correct
    assertEquals(viewModel.firstUserName, UserAlice.name)
}

جایگزین کردن UserRepository با یک جعلی در تست واحد آسان است، زیرا ViewModel توسط تستر ایجاد می‌شود. با این حال، جایگزینی عناصر دلخواه در آزمایش های بزرگتر می تواند چالش برانگیز باشد.

جایگزینی اجزا و تزریق وابستگی

وقتی تست‌ها هیچ کنترلی بر ایجاد سیستم‌های تحت آزمایش ندارند، جایگزینی اجزا برای دوتایی‌های آزمایشی بیشتر درگیر می‌شود و به معماری برنامه‌تان نیاز دارد که از طراحی قابل آزمایش پیروی کند.

حتی تست‌های انتها به انتها بزرگ نیز می‌توانند از استفاده از تست‌های دوتایی بهره ببرند، مانند تست UI ابزاری که در جریان یک کاربر کامل در برنامه شما حرکت می‌کند. در این صورت ممکن است بخواهید آزمایش خود را هرمتیک کنید. تست هرمتیک از تمام وابستگی های خارجی مانند واکشی داده ها از اینترنت جلوگیری می کند. این قابلیت اطمینان و عملکرد را بهبود می بخشد.

شکل 2 : یک آزمایش بزرگ که بیشتر برنامه را پوشش می دهد و داده های راه دور را جعل می کند.

شما می توانید برنامه خود را طوری طراحی کنید که به این انعطاف پذیری دستی دست یابد، اما توصیه می کنیم از یک چارچوب تزریق وابستگی مانند Hilt برای جایگزینی اجزای برنامه خود در زمان تست استفاده کنید. راهنمای تست Hilt را ببینید.

روبولکتریک

در اندروید می‌توانید از چارچوب Robolectric استفاده کنید که نوع خاصی از تست دوبل را ارائه می‌کند. Robolectric به شما امکان می دهد تست های خود را در ایستگاه کاری خود یا در محیط یکپارچه سازی مداوم خود اجرا کنید. از یک JVM معمولی، بدون شبیه ساز یا دستگاه استفاده می کند. این تورم نماها، بارگیری منابع و سایر بخش‌های چارچوب اندروید را با دو تست به نام سایه‌ها شبیه‌سازی می‌کند.

Robolectric یک شبیه ساز است بنابراین نباید جایگزین تست های واحد ساده شود یا برای انجام تست سازگاری استفاده شود. سرعت را فراهم می کند و در برخی موارد هزینه را به قیمت وفاداری کمتر کاهش می دهد. یک رویکرد خوب برای تست‌های UI این است که آن‌ها را با تست‌های Robolectric و instrumented سازگار کنیم و بسته به نیاز به آزمایش عملکرد یا سازگاری، تصمیم بگیریم که چه زمانی آنها را اجرا کنیم. هر دو تست Espresso و Compose می توانند روی Robolectric اجرا شوند.