مقدمه:
نوشتن کد قابل تست یکی از مهمترین مراحل در توسعه نرمافزار است که به شما کمک میکند از کیفیت و عملکرد برنامه خود اطمینان حاصل کنید. در کاتلین، همانطور که در زبانهای برنامهنویسی دیگر استفاده میشود، رویکردهای مختلفی برای نوشتن کد قابل تست وجود دارد که در ادامه به این موضوع میپردازیم.
1. از تزریق وابستگی استفاده کنید
تزریق وابستگی فرآیندی است که در آن یک منبع یا شی به یک قطعه کد مشخص می شود. تزریق وابستگی یک الگوی کد قدرتمند است که به دستیابی به کد تمیز و قابل آزمایش کمک می کند.
مثال:
در اینجا، ما از الگوی singleton برای DI (تزریق وابستگی) برای اهداف نمایشی استفاده میکنیم. با این حال، می توانید از فریم ورک های Hilt یا Koin برای DI استفاده کنید. یک چیز وجود دارد که باید بر آن تأکید شود: هنگام ارائه وابستگی LoginRepositoryImpl، ما فقط Interfaces را برای اهداف آزمایشی ارائه می دهیم، همانطور که در کلاس LoginViewModelTest می بینید.
در LoginViewModelTest، ما رابط LoginRepository را به mock میکنیم که آزمایش را آسان تر می کند.
2. استفاده از Interfaces
استفاده از Interfaces برای تست یکی از الزامات اساسی است. در پایگاه کد، هر کلاسی که نیازمندیهای پیادهسازی مانند repository، data source، API و ... را دارد، میتواند با استفاده از متدهای Interfaces کپسوله شود. داشتن یک Interfaces روی یک کلاس پیاده سازی(implementation) برای ایجاد یک محیط تست خوب، تمرین خوبی است.
مثال:
در طول تست، می توانید به راحتی برای LoginRepository بدون افشای غیر ضروری پیاده سازی(implementation) واقعی، mocks هایی ایجاد کنید.
نکته: mock چیست؟ در واقع Mock کردن (Mocking) یک تکنیک تست نویسی است که در آن قسمتی از کد را با یک پیاده سازی دلخواه جایگزین میکنیم و از آن برای شبیه سازی یک عملیات واقعی استفاده میشه. معمولا ماک کردن زمانی استفاده میشه که یک متد یا کلاس، وابستگی یا وابستگی هایی داره که توی تستمون تداخل ایجاد میکنه.
3. از توابع کوچک استفاده کنید
در معماری تمیز، توابع کوچک مهمترین بخش نوشتن کدهای تمیز و قابل آزمایش هستند. از نظر فنی، نوشتن functions کوچک به یک طرز فکر کامل نیاز دارد. گاهی اوقات، با نوشتن یک تابع و سپس تغییر ساختار آن به چندین توابع کوچک شروع می شود. این فرآیند شبیه به تجزیه یک منطق غول پیکر به چند functions کوچک است، و شما می توانید functions را در صورت نیاز در طول مسیر بشکنید.
به عنوان مثال، هنگامی که یک تابع برای ورود به سیستم با منطق داخلی متفاوت می نویسید، این منطق های داخلی مختلف می توانند به توابع کوچک تقسیم شوند. هر تابع یک منطق یا مسئولیت واحد را فراخوانی می کند.
نوشتن این توابع کوچک در یک شی Companion برای جداسازی بیشتر و کد قابل تست است. هر function کوچک یک مسئولیت را انجام می دهد. در حین تست، می توانید به راحتی invoke توابع شی Companion را برای تست responsibility کنید.
مثال:
4. از دسترسی به Framework ها و کتابخانه خودداری کنید
استفاده از کلاسها یا توابع فریمورک یا کتابخانه در کد، آزمایش را سختتر میکند، زیرا به سختی میتوان کلاسهای داخلی را Mock کرد. کد قابل آزمایش باید از دسترسی مستقیم به کلاس های Framework یا کتابخانه ها جلوگیری کند.
بیشتر اوقات از الگوی طراحی Factory برای ایجاد اشیا استفاده می شود. این شی می تواند یک پیاده سازی concrete یا یک plain class ساده باشد. استفاده از الگوی factory یکی از مفیدترین الگوها هنگام دسترسی به Framework ها یا کتابخانه ها در کدهای قابل تست است.
مثال:
در کد، ما از یک factory برای ایجاد شی SearchClient استفاده می کنیم. در عین حال، ما جستجوی داخلی (internal search) client SDK را در معرض repository و view model قرار نمی دهیم. اینگونه است که از استفاده مستقیم از کلاس های Framework یا کتابخانه اجتناب می کنیم.
همچنین، اگر به کد دقت کرده باشید، جستجوی داخلی ما client SDK به چرخه حیات fragment یا activity متصل است که به یک context نیاز دارد. ما SearchClient را به عنوان یک آرگومان برای تابع جستجو در SearchViewModel می گیریم تا از دسترسی context یا framework-level جلوگیری کنیم.
در طول تست SearchViewModel، میتوانید به راحتی SearchClient را بدون ارائه کلاسهای context یا internal SDK ماک (mock) کنید.
ممنون که تا آخر این پست همراه من بودید ، امیدوارم براتون مفید بوده باشه 🙌🙏✌ (:
بقیه آموزش های mister developer را می توانید در تلگرام و اینستاگرام دنبال کنید!!
کانال تلگرام: mister_developerr
اینستاگرام: mister_developerr
موفق و پیروز باشید