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

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

همه تستهای واحد محلی نیستند و همه تستهای سرتاسری روی یک دستگاه اجرا نمیشوند. برای مثال:
- تست محلی بزرگ : میتوانید از یک شبیهساز اندروید که به صورت محلی اجرا میشود، مانند Robolectric ، استفاده کنید.
- تست ابزاری کوچک : میتوانید تأیید کنید که کد شما با یک ویژگی چارچوب، مانند پایگاه داده SQLite، به خوبی کار میکند. میتوانید این تست را روی چندین دستگاه اجرا کنید تا ادغام با نسخههای مختلف SQLite را بررسی کنید.
مثالها
قطعه کدهای زیر نحوه تعامل با رابط کاربری را در یک تست رابط کاربری ابزاری نشان میدهند که روی یک عنصر کلیک میکند و نمایش عنصر دیگری را تأیید میکند.
اسپرسو
// When the Continue button is clicked
onView(withText("Continue"))
.perform(click())
// Then the Welcome screen is displayed
onView(withText("Welcome"))
.check(matches(isDisplayed()))
رابط کاربری را بنویسید
// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()
// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()
این قطعه کد بخشی از یک تست واحد برای یک ViewModel (تست محلی، سمت میزبان) را نشان میدهد:
// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)
// When data is loaded
viewModel.loadData()
// Then it should be exposing data
assertTrue(viewModel.data != null)
معماری قابل آزمایش
با یک معماری برنامه قابل آزمایش، کد از ساختاری پیروی میکند که به شما امکان میدهد به راحتی بخشهای مختلف آن را به صورت جداگانه آزمایش کنید. معماریهای قابل آزمایش مزایای دیگری مانند خوانایی بهتر، قابلیت نگهداری، مقیاسپذیری و قابلیت استفاده مجدد دارند.
معماری که قابل آزمایش نباشد، موارد زیر را ایجاد میکند:
- تستهای بزرگتر، کندتر و ناپایدارتر. کلاسهایی که نمیتوانند تست واحد شوند، ممکن است مجبور شوند توسط تستهای یکپارچهسازی بزرگتر یا تستهای رابط کاربری پوشش داده شوند.
- فرصتهای کمتر برای آزمایش سناریوهای مختلف. آزمایشهای بزرگتر کندتر هستند، بنابراین آزمایش تمام حالتهای ممکن یک برنامه ممکن است غیرواقعی باشد.
برای کسب اطلاعات بیشتر در مورد دستورالعملهای معماری، به راهنمای معماری برنامه مراجعه کنید.
رویکردهای جداسازی
اگر بتوانید بخشی از یک تابع، کلاس یا ماژول را از بقیه جدا کنید، آزمایش آن آسانتر و مؤثرتر خواهد بود. این عمل به عنوان جداسازی شناخته میشود و مفهومی است که برای معماری قابل آزمایش بسیار مهم است.
تکنیکهای رایج برای جداسازی شامل موارد زیر است:
- یک برنامه را به لایههایی مانند Presentation، Domain و Data تقسیم کنید. همچنین میتوانید یک برنامه را به ماژولهایی تقسیم کنید، هر ماژول برای هر ویژگی.
- از اضافه کردن منطق به موجودیتهایی که وابستگیهای زیادی دارند، مانند فعالیتها و فرگمنتها، خودداری کنید. از این کلاسها به عنوان نقاط ورودی به چارچوب استفاده کنید و منطق رابط کاربری و کسبوکار را به جای دیگری، مانند یک لایه Composable، ViewModel یا دامنه، منتقل کنید.
- از وابستگیهای مستقیم به فریمورک در کلاسهای حاوی منطق تجاری خودداری کنید. برای مثال، از Android Contexts در ViewModels استفاده نکنید .
- جایگزینی وابستگیها را آسان کنید. برای مثال، به جای پیادهسازیهای مشخص، از رابطها استفاده کنید. حتی اگر از چارچوب DI استفاده نمیکنید، از تزریق وابستگی استفاده کنید.
مراحل بعدی
حالا که میدانید چرا باید تست بزنید و دو نوع اصلی تست را میدانید، میتوانید «چه چیزی را تست کنیم» را بخوانید یا در مورد استراتژیهای تست یاد بگیرید.
از طرف دیگر، اگر میخواهید اولین تست خود را ایجاد کنید و با انجام دادن آن یاد بگیرید، Testing codelabs را بررسی کنید.