تست نویسی در فرانت اند

شاید به دفعات در مورد تست نویسی در فرانت‌اند شنیده باشید. در این مقاله تلاش می‌کنم این موضوع رو مقداری توضیح بدم و در مقالات بعدی با نوشتن چند نمونه کد کاربردی برای هر بخش و نوشتن تست اتوماتیک به وسیله CI/CD در گیت لب به پایان برسانم.اهمیت تست نویسی بر هیچ فردی پوشیده نیست. وقتی مقیاس پروژه بزرگ می شود یا وقتی افراد مختلفی روی یک پروژه کار می کنند یا زمانی که یک پروژه در یک بازه زمانی طولانی در حال توسعه و نگهداری باشد، استفاده از تست نویسی اهمیت پیدا می کند. بوسیله تست نویسی می توانیم خروجی فعلی نرم افزار را با خروجی مورد انتظار (Expected) مقایسه کنیم و در صورت بروز خطا به بررسی و رفع مشکل بپردازیم.Testing Pyramid کاربردی‌ترین تست‌های فرانت‌اند:JavaScript Testing تست واحد (Unit Testing):تست واحد یک مرحله از تست نرم افزار است که در آن کوچکترین بخش از یک برنامه مثل یک تابع یا کامپوننت یا ماژول با ارائه ورودی و اطمینان از اینکه خروجی مطابق انتظار ماست به صورت مستقل مورد تست قرار می‌گیرد. در تست واحد نباید هیچ تستی به تست دیگری وابسته باشد. در هنگام نوشتن تست واحد به نحوی شما مشغول نوشتن مستندات برای کدهایتان هستید که منجر به کدبیس تمیزتر می‌شود. معمولا در تست واحد، دقت تست زیاد و از طرفی تعداد تست ها نیز بیشتر از حالات دیگر است. معمولا قبل از هر کامیتی باید تست اجرا شود تا صحت آن بررسی شود، همچنین خیلی از شرکت ها اجازه push کردن کدها قبل از نوشتن تست برای آنها را نمی‌دهند.مهم ترین نکات در هنگام نوشتن Unit Test:1- تست باید خیلی خیلی ساده باشد تا سریع و در مدت زمان کمی اجرا شود. (یعنی تست‌ها باید کوچک باشند تا تغییر در کد آسان‌تر باشد.)2- تست‌ها باید ایزوله و مستقل از همدیگر و هیچ وابستگی‌ای به هم نداشته باشند.3- تست‌ها نباید وابستگی به محیط و زمان اجرا داشته باشند. (تست باید همیشه در هر محیط و زمانی یک خروجی مشخص داشته باشد.)4- خروجی تست باید حتما به صورت Pass یا Fail باشد و نیاز به بررسی های بیشتر نداشته باشد.5- حتما برای باگ‌ها قبل از debug تست بنویسید تا از بروز مجددا آن ها جلوگیری شود.تست یکپارچگی(Integration Testing):تست یکپارچگی مهمترین سطح از تست است که روی تعامل بین اجزا، ماژول‌ها و اشیایی که با هم کار می‌کنند، تمرکز دارد. تست یکپارچگی در واقع سطحی از تست است که اطمینان می‌دهد بخش‌های مختلف سیستم به درستی باهم تعامل دارند و داده‌ها و اطلاعات بین آنها به درستی پاس داده می‌شود. درتست یکپارچگی ماژول‌های نرم‌افزاری به صورت Logical یکپارچه شده و به صورت گروهی تست می‌شوند.Unit Test vs Integration Test یک پروژه معمولا شامل چندین ماژول می باشد که توسط برنامه نویسان مختلف توسعه داده شده است. هدف از تست یکپارچه‌سازی، پیدا کردن خطاهایی است که پس از یکپارچه کردن ماژول‌ها بوجود می آیند. تمرکز اصلی این تست، بررسی ارتباط داده‌ها بین ماژول‌هاست و شیوه کاری کامپوننت‌ها با یکدیگر را بررسی می کند.بعد از اینکه کدها در کامپوننت‌های متفاوتی از یکدیگر قرار گرفتند، نیاز داریم که شیوه کار کردن آن‌ها با یکدیگر را تست کنیم. مثلا اگر لایه احراز هویت نتواند دیتایی که از دیتابیس برگشت داده می‌شود را درک کند، هیچ فردی قادر به انجام فرایند login نخواهد بود. این موارد شیوه کار کردن یک قسمت از اپلیکیشن با دیگر بخش‌ها را بررسی می‌کند. در حالی که تست‌های واحد از همدیگر جدا هستند و در واقع در یک فضای ایزوله شده قرار می‌گیرند، تست‌های یکپارچه‌سازی روی بخش‌هایی که ساید افکت دارند و یا ارتباط داشتن بین دو یا چند قسمت یا بخش‌هایی که نیازمند قسمت‌های دیگر سیستم هستند تمرکز دارند.از آنجایی که انجام تست یکپارچه‌سازی به بررسی قسمت‌های مختلفی می‌پردازد در نهایت کندتر خواهد بود. بنابراین باید کمتر از آن‌ها استفاده شود. به صورت ایده‌آل از این تست تنها در زمانی استفاده می‌شود که یک ویژگی‌ به صورت کامل ایجاد شده باشد.Integration Testingبرای نوشتن تست واحد و تست یکپارچگی در جاوا اسکریپت می توان از فریمورک Jest استفاده کرد.Jest Frameworkجست (Jest):یک فریمورک محبوب برای نوشتن تست در جاوا اسکریپت است که توسط فیسبوک ارائه شده و تمرکز آن بر روی سادگی‌ست و با تمامی فریمورک‌های محبوب جاوا اسکریپت مثل React, Angular, Vue و … کار می‌کند. برخی از ویژگی‌های jest:بدون پیکربندیماک (Mock) نویسی سادهانجام تست‌ها به صورت موازیسرعت فوق العادهمستندات بسیار خوبفریمورک های زیادی برا ی تست نویسی وجود دارد ولی jest یک چیز دیگست!Jest Installation‍‍‍:$ npm install --save-dev jest # or $ yarn add --dev jestJest Example:# sum.js function sum(a, b) { return a + b; } module.exports = sum; # sum.test.js const sum = require('./sum'); test('adds 1 + 2 to equal 3', () => { expect(sum(1, 2)).toBe(3); });Run Test:$ npm run test # or $ yarn testتست ارتباط کاربر با نرم افزار (End-to-End Testing):بالاترین سطح از تست‌های خودکار فرآیندی معروف به «End-to-End» می‌باشد که به عنوان تست «E2E» یا «Functional Test» هم شناخته می‌شود.سیستم‌های نرم افزاری امروزی بسیار پیچیده شده‌اند و با زیرسیستم‌های متعددی در ارتباط هستند. اگر هر یک از زیرسیستم‌ها دچار مشکل شوند و کرش کنند، کل سیستم نرم افزاری ممکن است از کار بیفتد. می‌توان با تست E2E از این قبیل مشکلات مطلع شد.هدف اصلی از تست E2E آزمایش تجربه کاربر نهایی با شبیه سازی سناریوی واقعی کاربر و اعتبارسنجی سیستم تحت آزمایش و اجزای آن برای یکپارچگی است. در این سطح تمام اکشن‌های کاربر از ابتدای وارد شدن به سیستم تا آخرین مرحله شبیه سازی می شود.تست‌های E2E توسط یک برنامه نرم‌افزاری اجرا می‌شوند که کلیک و رفتار انسان را شبیه‌سازی می‌کند تا ببیند آیا رفتار برنامه شما درست است یا خیر؟ نوشتن این نوع تست‌ها مقداری زمان بر است. از آنجایی که این تست‌ها مبتنی بر رابط کاربری هستند بنابراین با تغییرات رابط کاربری بروزرسانی می شوند.Puppeteer ابزارهایی مانند Puppeteer می‌توانند در نوشتن چنین تست‌هایی بسیار کارآمد باشند. Puppeteer بطور کلی مرورگر و همچنین رفتار کاربران را مانند یک ربات شبیه سازی می کند. مثلا می توان تعریف کرد که puppeteer کلیک کاربر روی یک input، تایپ کردن متن در آن و کلیک روی دکمه submit را شبیه سازی کند.چرخه حیات یک تست E2E:E2E Test life-cycleInstallation Puppeteer:$ npm install --save-dev puppeteer # or $ yarn add --dev puppeteerPuppeteer Example:# index.html <!DOCYTYPE html> <head> <title>E2E Testing</title> </head> <body> <div class=&quotheader&quot> <div class=&quotcontainer&quot> <h1>Add New Product</h1> </div> </div> <div class=&quotcontainer main&quot> <div> <input type=&quottext&quot id=&quottitle&quot placeholder=&quotProduct Title...&quot> </div> <div> <input type=&quottext&quot id=&quotprice&quot placeholder=&quotProduct Price...&quot> </div> <button id=&quotadd-product&quot>Add Product</button> </div> <div class=&quotproducts&quot> <ul></ul> </div> </body> </html># util.test.js const puppeteer = require('puppeteer'); test('clicked', async () => { const browser = await puppeteer.launch({ headless: false, slowMo: 80, args: ['--window-size=1920,1080'] }); const page = await browser.newPage(); await page.goto('http://127.0.0.1:8080/'); await page.click('#title'); await page.type('#title', 'Book'); await page.click('#price'); await page.type('#price', '79'); await page.click('#add-product'); });Run Test:$ npm run test # or $ yarn testSample E2E Testامیدواریم این مطلب مفید واقع شده باشد. موفق باشید :)