از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
راهنمای قطعی تست واحد در برنامه های React با Jest و React-Testing به عنوان یک توسعه دهنده، یکی از مواردی که در بالای لیست شما قرار دارد باید ارسال کد بدون اشکال باشد. هیچ چیز بدتر از فهمیدن نیست روی پنجشنبه شب که تغییراتی که دادی روی دوشنبه برنامه زنده را شکست. تنها راه برای اطمینان از اینکه برنامه شما مطابق با…
سرفصلهای مطلب
معرفی
به عنوان یک توسعه دهنده، یکی از چیزهایی که در بالای لیست شما قرار دارد باید ارسال کد بدون اشکال باشد. هیچ چیز بدتر از فهمیدن نیست روی پنجشنبه شب که تغییراتی که دادی روی دوشنبه برنامه زنده را شکست. تنها راه برای اطمینان از اینکه برنامه شما مطابق با نیازهای سیستم و کاربر کار می کند این است امتحانش کن!
تست یکی از اجزای حیاتی هر چرخه عمر توسعه نرم افزار است و تضمین می کند که یک نرم افزار به درستی و طبق برنامه عمل می کند. توسعه وب، توسعه اپلیکیشن موبایل، و به طور قابل توجهی در زمینه ما، برنامه های React همگی از اصول یکسانی پیروی می کنند.
اجزای React را می توان به چند روش مختلف آزمایش کرد که به طور کلی به دو گروه تقسیم می شوند:
- ارائه درختان جزء در یک محیط آزمایشی ساده و اظهار نظر در مورد عملکرد آنها
- در حال دویدن “آزمون های انتها به انتها”، که شامل آزمایش کل یک برنامه در یک محیط مرورگر واقعی است
در حالی که آزمایش برنامههای React ممکن است به روشهای مختلفی انجام شود، در این راهنما، ما یک برنامه React ایجاد میکنیم و راهنمای کاملی درباره روش انجام تستهای واحد را پوشش میدهیم. روی برنامه React با استفاده از شوخی و کتابخانه تست واکنش به طوری که می توانید مهارت های تست خود را تقویت کنید و یاد بگیرید که چگونه یک برنامه رام React ایجاد کنید.
تست چیست؟
اول از همه، اجازه دهید همه چیز را در یک چشم انداز قرار دهیم. آزمایش کردن یک اصطلاح بسیار گسترده است و می تواند به تست دستی، تست واحد، تست رگرسیون، تست یکپارچه سازی، تست بار و غیره اشاره داشته باشد.
در چارچوب تست واحد که تمرکز خواهیم کرد روی امروز – ما تست می کنیم عملکرد واحدهای متمایز، معمولا روی یک سطح روش این می تواند مقادیر عددی خروجی ها، طول مقادیر خروجی، شکل آنها، روش واکنش روش به ورودی نامعتبر و غیره را آزمایش کند.
از آنجایی که اکثر روشهای نرمافزاری خوب از روشها/عملکردهای کوتاه و عملی دفاع میکنند که دارای هدف مشخصی هستند، بسیاری از روشها را فراخوانی میکنند. روش های دیگر. به طور معمول، شما باید هم روشهای داخلی و هم روشهای خارجی را آزمایش کنید تا مطمئن شوید که تغییراتی که در حین اصلاح، رفع اشکال یا بهبود یک ویژگی ایجاد میکنید، هیچ عملکرد دیگری را خراب نمیکند.
که در توسعه تست محور (TDD)، توصیه می شود قبل از نوشتن منطق یک روش، یک تست و مقدار مورد انتظار بنویسید. طبیعتاً در ابتدا شکست خواهد خورد. پس از آن، شما فقط آن را به کار میگیرید، و وقتی تست را پشت سر گذاشت، شروع به بازسازی آن میکنید تا کوتاهتر، تمیزتر، سریعتر و غیره شود. تا زمانی که خروجی ثابت بماند، میدانید که چیزی را خراب نکردهاید. در حین بازسازی!
نوشتن تست های واحد خود شما را در ذهنیت یک نفر قرار می دهد استفاده کردن روش های شما، به جای کسی نوشتن این روشها، که اغلب به نگاهی تازه به یک ویژگی کمک میکنند، بررسیهای اضافی و اعتبارسنجی و شکار باگها را شامل میشوند. گاهی اوقات، منجر به تغییرات طراحی برای ایجاد کد می شود قابل آزمایش تر، مانند عملکرد جداسازی برای فعال کردن آزمایش عددی برای هر جزء جداگانه.
هنگامی که یک خط مبنا ایجاد شد، و کد شما تست ها را پشت سر گذاشت، می توانید تغییراتی ایجاد کنید و تأیید کنید که واحدها (معمولاً روش ها) به صورت جداگانه کار می کنند. آزمایش به ویژه زمانی مفید است که بهروزرسانیهایی در پایگاه کد وجود داشته باشد.
رویکردهای آزمایش
آزمایش را می توان به دو روش مختلف انجام داد: به صورت دستی و بطور خودکار. با تعامل مستقیم با یک برنامه، آزمایش دستی عملکرد صحیح آن را تأیید می کند. تست خودکار تمرین نوشتن برنامه ها برای انجام بررسی ها برای شما است.
تست دستی
اکثر توسعه دهندگان به صورت دستی کد خود را بررسی می کنند، زیرا این سریع ترین، طبیعی ترین و ساده ترین راه برای آزمایش سریع یک عملکرد است.
آزمایش دستی مرحله منطقی بعدی است که پس از نوشتن عملکرد انجام می شود، درست مانند چشیدن یک غذا پس از چاشنی کردن آن (اضافه کردن یک ویژگی) تا بررسی شود که آیا آن طور که در نظر گرفته شده کار می کند یا خیر.
فرض کنید که به عنوان یک توسعه دهنده شاغل، در حال ساخت یک فرم ثبت نام هستید. شما به سادگی ویرایشگر متن خود را نمی بندید و به رئیس خود اطلاع نمی دهید که فرم پس از کدنویسی کامل شده است. مرورگر را باز میکنید، از طریق فرم ثبتنام بروید processو مطمئن شوید که همه چیز طبق برنامه پیش می رود. به عبارت دیگر، شما به صورت دستی کد را آزمایش خواهید کرد.
تست دستی برای پروژههای کوچک ایدهآل است و اگر یک برنامه فهرست کار دارید که میتوانید هر دو دقیقه آن را به صورت دستی بررسی کنید، نیازی به تستهای خودکار ندارید. با این حال، بسته به روی تست دستی با رشد برنامه شما دشوار می شود – شاید از دست دادن تمرکز و فراموش کردن بررسی چیزی بسیار آسان باشد. با یک لیست رو به رشد از اجزای متقابل، تست دستی حتی سخت تر می شود، به خصوص اگر چیزی را آزمایش کرده باشید، و به یک مورد جدید پیشرفت کرده باشید و آخرین ویژگی را شکسته باشید، بنابراین برای مدتی آن را دوباره آزمایش نمی کنید و نمی دانید اکنون خراب است.
به زبان ساده، آزمایش دستی برای شروع کار خوب است – اما به خوبی مقیاس نمی شود و کیفیت کد را برای پروژه های بزرگتر تضمین نمی کند. خبر خوب این است که رایانه ها در کارهایی مانند این عالی هستند، ما باید از تست های خودکار تشکر کنیم!
تست خودکار
در تست خودکار، کد اضافی برای آزمایش کد برنامه خود می نویسید. بعد از اینکه کد تست را نوشتید، می توانید برنامه خود را هر چند بار که می خواهید با حداقل تلاش آزمایش کنید.
تکنیک های متعددی برای نوشتن تست های خودکار وجود دارد:
- نوشتن برنامه هایی برای خودکارسازی مرورگر،
- فراخوانی توابع به طور مستقیم از کد منبع شما،
- مقایسه اسکرین شات های برنامه رندر شده شما…
هر تکنیک مجموعه ای از مزایای خاص خود را دارد، اما همه آنها یک چیز مشترک دارند – آنها در زمان شما صرفه جویی می کنند و کیفیت کد بالاتر را نسبت به آزمایش دستی تضمین می کنند!
تست های خودکار برای اطمینان از اینکه برنامه شما طبق برنامه ریزی انجام می شود عالی هستند. آنها همچنین مرور تغییرات کد را در یک برنامه آسان تر می کنند.
انواع تست
تا کنون، ما به تست ها در سطح بالایی نگاه کرده ایم. زمان آن فرا رسیده است که در مورد انواع مختلف آزمون هایی که می توان نوشتند بحث کرد.
سه نوع تست برنامه کاربردی front-end وجود دارد:
-
تست های واحد: در تست های واحد، تک تک واحدها یا اجزای نرم افزار تست می شوند. یک واحد منفرد یک تابع، روش، رویه، ماژول، جزء یا شیء واحد است. تست واحد، بخشی از کد را جداسازی و تأیید میکند تا تأیید کند که هر واحد از کد نرمافزار مطابق انتظار عمل میکند.
ماژول ها یا توابع مجزا در تست واحد آزمایش می شوند تا اطمینان حاصل شود که همانطور که باید به درستی کار می کنند و همه اجزاء نیز به صورت جداگانه آزمایش می شوند. برای مثال، تست واحد شامل تعیین اینکه آیا یک تابع، یک دستور یا یک حلقه در یک برنامه به درستی کار می کند یا خیر. -
تست های عکس فوری: این نوع آزمایش تضمین می کند که رابط کاربری (UI) یک برنامه وب به طور غیر منتظره تغییر نمی کند. کد یک کامپوننت را در یک نقطه زمانی خاص می گیرد و به ما امکان می دهد کامپوننت را در یک حالت با هر حالت ممکن دیگری که می تواند داشته باشد مقایسه کنیم.
یک سناریوی تست اسنپ شات معمولی شامل رندر کردن یک مؤلفه رابط کاربری، گرفتن یک عکس فوری و مقایسه آن با یک فایل عکس فوری مرجع است که همراه با آزمون نگهداری می شود. اگر دو عکس فوری متفاوت باشند، آزمایش ناموفق خواهد بود زیرا تغییر یا غیرمنتظره بوده است یا باید عکس فوری مرجع بهروزرسانی شود تا مؤلفه رابط کاربری جدید را منعکس کند. -
تست های پایان به انتها: آزمون های پایان به پایان ساده ترین نوع آزمون برای درک هستند. آزمایشهای سرتاسری در برنامههای فرانتاند، مرورگر را خودکار میکند تا اطمینان حاصل شود که یک برنامه از دیدگاه کاربر به درستی کار میکند.
تست های انتها به انتها در زمان بسیار صرفه جویی می کنند. بعد از نوشتن، میتوانید هر چند بار که بخواهید یک تست سرتاسری را اجرا کنید. در نظر بگیرید که مجموعهای از صدها تست میتواند در مقایسه با نوشتن تستهای هر واحد مجزا چقدر زمان صرفهجویی کند.
با تمام مزایایی که به ارمغان می آورد، تست های انتها به انتها چند مشکل دارند. برای شروع، تست های انتها به انتها زمان بر هستند. یکی دیگر از مسائل مربوط به تست های انتها به انتها این است که اشکال زدایی آنها ممکن است دشوار باشد.
توجه داشته باشید: برای جلوگیری از مشکلات تکرارپذیری، آزمایشهای سرتاسری را میتوان در یک محیط تکرارپذیر اجرا کرد، مانند داکر container. کانتینرهای Docker و آزمایشهای سرتاسری خارج از محدوده این راهنما هستند، اما اگر میخواهید آزمایشهای سرتاسری را اجرا کنید تا از مشکل خرابی جلوگیری کنید، باید آنها را بررسی کنید. روی ماشین های مختلف
اگر میخواهید اصول اولیه آزمایش انتها به انتها با Cypress را درک کنید – ما را بخوانید “تست انتها به انتها در جاوا اسکریپت با Cypress”!
مزایا و معایب تست
در حالی که آزمایش مهم است و باید انجام شود، طبق معمول، هم مزایا و هم معایبی دارد.
مزایای
- از پسرفت غیرمنتظره محافظت می کند
- تست صحیح به طور قابل توجهی کیفیت کد را افزایش می دهد
- این به توسعه دهنده اجازه می دهد تا تمرکز کند روی وظیفه فعلی به جای گذشته
- ساخت ماژولار برنامههایی را که ساختن آنها سخت است را امکانپذیر میسازد
- نیاز به تأیید دستی را از بین می برد
معایب
- شما باید علاوه بر اشکال زدایی و نگهداری کد بیشتری بنویسید، و بسیاری احساس می کنند که بدون در نظر گرفتن مزایا، در پروژه های کوچکتر سربار غیرضروری است.
- خرابیهای تست غیر بحرانی/خوش خیم ممکن است منجر به رد شدن برنامه در طول یکپارچهسازی مداوم شود
بررسی اجمالی تست واحد
تا اینجا به طور کلی نگاهی به تست انداختیم. اکنون زمان آن است که به تمام موارد مربوط به تست واحد و روش نوشتن تست های واحد در برنامه های React بپردازیم!
قبل از تعریف تست واحد، لازم است بدانیم که یک روش تست خوب هدف آن سرعت بخشیدن به زمان توسعه، کاهش باگ ها در یک برنامه و بهبود کیفیت کد است، در حالی که یک رویکرد تست ضعیف یک برنامه را فلج می کند. در نتیجه، به عنوان توسعه دهندگان نرم افزار، ما باید رویکردهای موثر تست واحد را یاد بگیریم و یکی از آنها تست واحد است.
یک تعریف ساده از تست این است که آن است process بررسی عملکرد صحیح یک برنامه تست واحد است process آزمایش های در حال اجرا بر روی اجزا یا عملکردهای یک برنامه کاربردی. تستهای واحد، توابعی هستند که نسخههای مجزا از توابع موجود در کد منبع شما را فراخوانی میکنند تا بررسی کنند که آنها همانطور که باید و به طور قطعی رفتار میکنند.
نکات مثبت تست های واحد
تستهای واحد سریع هستند و میتوانند در چند ثانیه اجرا شوند (چه به صورت جداگانه برای یک ویژگی جدید و چه به صورت سراسری همه آزمایشها را اجرا کنند)، که به توسعهدهندگان بازخورد فوری میدهد. روی آیا یک ویژگی خراب است یا خیر. آنها همچنین به ارائه مستندات کمک می کنند، زیرا اگر یک توسعه دهنده جدید به یک پروژه ملحق شود، باید بدانند واحدهای مختلف پایگاه کد چگونه رفتار می کنند. این را می توان با مشاهده نتایج آزمون های واحد فهمید.
معایب آزمون های واحد
در حالی که تست های واحد جنبه های خوبی دارند، اما مشکلات خاص خود را نیز دارند. یک مشکل این است که وقتی صحبت از آن به میان می آید، کد refactoring است تغییرات طراحی، زیرا اینها با آزمون های واحد دشوارتر هستند. مثلاً، یک تابع پیچیده با تست های واحد آن دارید و می خواهید آن تابع را به چندین تابع مدولار تقسیم کنید. یک تست واحد احتمالاً برای آن تابع ناموفق خواهد بود، و باید آن را منسوخ کنید و دو تست واحد برای توابع تقسیم بنویسید. به همین دلیل است که تست واحد به طور ضمنی تقسیم آنها را از قبل و آزمایش جداگانه آنها را تشویق می کند، که منجر به مؤلفه های کد ماژولار و قابل آزمایش تر می شود. با این وجود، در برخی موارد، نمیتوانید تغییرات احتمالی را پیشبینی کنید، و مدت زمانی که برای بهروزرسانی آزمایشهای واحد طول میکشد، فرآیندهای بازسازی جدی را کمتر جذاب میکند.
مشکل دیگر تست واحد این است که فقط بخشهای جداگانه یک برنامه را بررسی میکند، حتی اگر آن بخش ترکیبی منطقی از چندین بخش کوچکتر باشد – هیچ واحد آزمایش برای کل برنامه بخشهای جداگانه یک برنامه ممکن است به درستی کار کنند، اما اگر روش رفتار آنها هنگام ترکیب آزمایش نشود، آزمایشها ممکن است بیفایده شوند. به همین دلیل است که تستهای واحد باید با تستهای سرتاسر یا تستهای ادغام یا در حالت ایدهآل – هر دو تکمیل شوند.
واحد تست یک React Application – Demo Project
بیایید نگاهی به یک مثال واقعی از واحد آزمایش یک برنامه React بیندازیم!
در این نسخه ی نمایشی، ما یک برنامه Counter را با تعداد زیادی بخش مختلف آزمایش خواهیم کرد. علیرغم اینکه شبیه یک برنامه بسیار ساده به نظر می رسد، به عنوان مثال خوبی برای یادگیری روش عملکرد تست واحد عمل می کند. ماهیت آزمایش این برنامه این است که جنبه های مختلفی از مؤلفه بستگی دارد روی روش تعامل کاربر با آن
راه اندازی پروژه
این create-react-app
دستور ساخته شده توسط تیم React، بهترین راه برای شروع ایجاد یک برنامه React در دنیای واقعی و در مقیاس بزرگ است زیرا آماده استفاده است و به راحتی با کتابخانه تست شوخی. اگر باز کنید package.json
فایل، خواهید دید که ما پشتیبانی پیش فرض برای آن داریم شوخی و کتابخانه تست واکنش در setupTests.js
فایل. در صورت نیاز، نیازی به نصب دستی Jest در پروژه خود نداریم!
اگر قبلاً از آن استفاده نکرده اید – آن را با آن اجرا کنید npx
، که آن را برای استفاده بعدی نصب می کند:
$ npx create-react-app react-unit-tests
اگر قبلاً این ابزار را نصب کرده اید، یک برنامه React ایجاد کنید و نام آن را بگذارید react-unit-tests
:
$ create-react-app react-unit-tests
توجه داشته باشید: npx
از آخرین نسخه استفاده می کند create-react-app
، در حالی که ممکن است نسخه جهانی نصب شده نباشد. به طور کلی توصیه می شود که ابزار را از طریق آن اجرا کنید npx
برای اطمینان از آخرین نسخه ها، مگر اینکه به طور هدفمند بخواهید از نسخه دیگری استفاده کنید.
سپس وارد دایرکتوری پروژه می شویم و سرور توسعه را راه اندازی می کنیم:
$ cd react-unit-tests && npm start
// OR
$ cd react-unit-tests && yarn start
این برنامه جدید ایجاد شده ما را در مرورگر خروجی می دهد localhost:3000
.
توجه داشته باشید: یک ویژگی مفید در اینجا این است که بارگذاری مجدد داغ به طور پیش فرض پشتیبانی می شود، بنابراین نیازی به بارگیری مجدد مرورگر برای مشاهده تغییرات جدید یا نصب دستی نیست nodemon
یا کتابخانه های مشابه
ساخت مولفه شمارنده
در src
دایرکتوری پروژه ما، یک فایل جدید به نام ایجاد کنید Counter.js
. که در Counter.js
، تمام قسمت های کامپوننت را تعریف می کنیم. این شامل توابع مختلف شمارنده، از جمله increment()
، decrement()
، restart()
، و switchSign()
، که با کلیک کردن، مقدار شمارش را از منفی به مثبت معکوس می کند. این توابع برای دستکاری مقدار شمارش اولیه (که به عنوان یک پایه ارسال می شود) ایجاد می شوند:
// Counter.js
import React, { useState } from "react";
function Counter({ initialCount }) {
const (count, setCount) = useState(initialCount);
const increment = () => {
setCount((prev) => prev + 1);
};
const decrement = () => {
setCount((prev) => prev - 1);
};
const restart = () => {
setCount(0);
};
const switchSign = () => {
setCount((prev) => prev * -1);
};
return (
<div>
<h1>
Count: <h3>{count}</h3>
</h1>
<div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={restart}>Restart</button>
<button onClick={switchSign}>Switch sign</button>
</div>
</div>
);
}
export default Counter;
سپس، به روز رسانی کنید App.js
:
// App.js
import "./App.css";
import Counter from "./Counter";
function App() {
return (
<div className="App">
<Counter />
</div>
);
}
export default App;
اکنون میتوانیم اپلیکیشن شمارنده را مشاهده کنیم روی مرورگر:
ایجاد تست برای کامپوننت ها
بیایید یک فایل آزمایشی به نام ایجاد کنیم Counter.test.js
برای نشان دادن آزمون مولفه Counter. حتما حذف کنید App.test.js
به طوری که در حین اجرای آزمایش نتایج ناخواسته ایجاد نکند.
توجه داشته باشید: یک روش معمول این است که فایل های آزمایشی خود را با پسوند نامگذاری کنید .test.js
، بازتاب نام فایل/جزئی که در حال آزمایش هستید. این امر تداوم بین فایلهای آزمایشی را تضمین میکند، تغییرات فقط در فایلهای مربوط به کدی که بهروزرسانی میکنید هنگام فشار دادن تغییرات (تعداد کمتر تداخل ادغام) ایجاد میشود و قابل خواندن است.
علاوه بر این، فایل های آزمایشی معمولاً در a قرار دارند /test
فهرست راهنما موازی به کد منبع شما root دایرکتوری، هر چند، این نیز وابسته به تیم است.
که در Counter.test.js
، اول ما import را Counter
جزء، سپس تست را با describe()
تابع برای توصیف تمام عملکردهای مختلف که ممکن است در کامپوننت اتفاق بیفتد.
این
describe()
تابع برای گروه بندی مجموعه های خاصی از تست هایی که ممکن است رخ دهد استفاده می شود روی یک جزء با استفاده از انواع مختلفit()
وtest()
مواد و روش ها. این نوعی بسته بندی منطقی است، که در آن شما، خوب، توصیف می کنید که یک سری از آزمایش ها با هر کدام چه می کنند.it()
یک تست عملکردی برای یک واحد است.
آزمایش مؤلفههای React شما میتواند به گونهای انجام شود که ما ممکن است از یک رندر آزمایشی برای ایجاد سریع یک مقدار قابل سریالسازی برای درخت React شما به جای ایجاد رابط کاربری گرافیکی استفاده کنیم، که شامل ایجاد برنامه کامل میشود.
آزمایش مقدار شمارنده اولیه
هنگام آزمایش، به ایجاد فهرستی منظم از ویژگیها و جنبههای یک ویژگی خاص کمک میکند – حالتهایی که اجزا میتوانند در آن قرار گیرند، چه چیزی میتواند بر آنها تأثیر بگذارد و غیره.
اولین چیزی که ما می خواهیم تست کنیم این است مقدار شمارش اولیه و چگونه کامپوننت با پایه ای که آن را تنظیم می کند کنترل می کند. با it()
روش، بررسی می کنیم که آیا برنامه شمارنده واقعاً مقدار دقیق شمارش اولیه را که به عنوان یک پایه ارسال شده است را نمایش می دهد یا خیر، که 0
در این مورد، و یک تابع فراخوانی را ارسال کنید که تمام اقداماتی را که در داخل آزمایش رخ می دهد، توصیف می کند:
// Counter.test.js
import { render, screen } from "@testing-library/react";
import Counter from "./Counter";
describe(Counter, () => {
it("counter displays correct initial count", () => {
render(<Counter initialCount={0} />);
expect(screen.getByTestId("count").textContent).toEqual(0);
});
});
در اینجا، ما از screen
نمونه ای از کتابخانه React Testing برای ارائه کامپوننت برای اهداف آزمایشی. ارائه یک نسخه ساختگی از یک مؤلفه برای آزمایش مفید است. و از آنجایی که <h3>
عنصری که count
مقدار موظف به تغییر پویا است، ما از آن استفاده می کنیم screen.getByTestId()
تابع برای گوش دادن به آن و واکشی ارزش آن با textContent
ویژگی.
توجه داشته باشید: این screen
تابع یک DOM منطبق برمی گرداند node برای هر پرس و جو یا در صورت یافتن هیچ عنصری خطا می دهد.
سپس، در Counter.js
جزء، ما به گوش <h3>
عنصر هنگام تست با تنظیم a data-testid
به عنصر دارای مقدار نسبت دهید count
:
// Counter.js
import React, { useState } from "react";
function Counter({ initialCount }) {
const (count, setCount) = useState(initialCount);
const increment = () => {
setCount((prev) => prev + 1);
};
const decrement = () => {
setCount((prev) => prev - 1);
};
const restart = () => {
setCount(0);
};
const switchSign = () => {
setCount((prev) => prev * -1);
};
return (
<div>
<h1>
<!-- Change here! -->
Count: <h3 data-testid="count">{count}</h3>
</h1>
<div>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={restart}>Restart</button>
<button onClick={switchSign}>Switch sign</button>
</div>
</div>
);
}
export default Counter;
برای تست اینکه آیا اولیه است count
مقدار برابر است 0
، ما استفاده می کنیم expect()
روشی برای توصیف آنچه از آزمونی که ما تنظیم کرده ایم انتظار می رود! در مورد ما، ما انتظار داریم که مقدار شمارش اولیه باشد 0
بنابراین ما از toEqual()
روشی که برای تعیین اینکه آیا مقادیر دو شیء مطابقت دارند یا خیر استفاده می شود. به جای تعیین هویت شی، toEqual()
matcher به صورت بازگشتی همه فیلدها را برای برابری بررسی می کند.
توجه داشته باشید: آزمون به طور خاص متمرکز است روی اطلاعاتی که ارائه می کنید؛ در مثال ما، یعنی Counter
جزء که دریافت کرده است initialCount
پشتیبانی این نشان می دهد که حتی اگر یک فایل دیگر—بگویید، اجازه دهید App.js
– دارای وسایل از دست رفته در Counter
جزء، آزمون همچنان با موفقیت پشت سر خواهد گذاشت زیرا صرفاً متمرکز است روی Counter.js
و روش استفاده از آن را نمی داند Counter
جزء. علاوه بر این، از آنجایی که تستها مستقل از یکدیگر هستند، رندر کردن یک جزء با پایههای مختلف در تستهای دیگر نیز تاثیری بر آن نخواهد داشت.
اکنون می توانیم تست مجموعه را اجرا کنیم:
$ yarn test
آزمون باید شکست بخورد:
FAIL src/Counter.test.js
Counter
× counter displays correct initial count (75 ms)
● Counter › counter displays correct initial count
expect(received).toEqual(expected) // deep equality
Expected: 0
Received: "0"
5 | it("counter displays correct initial count", () => {
6 | render(<Counter initialCount={0} />);
> 7 | expect(screen.getByTestId("count").textContent).toEqual(0);
| ^
8 | });
9 | });
10 |
at Object.<anonymous> (src/Counter.test.js:7:53)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.929 s, estimated 2 s
Ran all test suites related to changed files.
این آزمایش ناموفق بود زیرا ما یک عدد را در برابر یک رشته آزمایش کرده بودیم که نتیجه آن a خطای عمیق برابری. برای رفع آن، قالب را textContent
، یعنی مقدار اولیه، در تابع callback ما به عنوان یک عدد:
// Counter.test.js
import { render, screen } from "@testing-library/react";
import Counter from "./Counter";
describe(Counter, () => {
it("counter displays correct initial count", () => {
render(<Counter initialCount={0} />);
// Change here!
expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
});
});
اکنون، کد ما اولین آزمایش را با موفقیت پشت سر می گذارد:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (81 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.271 s
Ran all test suites related to changed files.
این یک مثال ساده از روش آزمایش است در حالی که نوشتن منطق به شما کمک میکند تا قبل از انباشته شدن بیشتر بدهیهای فناوری، از مشکلات بعدی جلوگیری کنید. آزمایش پیش از موعد نیز میتواند شما را قفل کند، زیرا در صورتی که مجبور به نوشتن مجدد تستها باشید، بازنویسی و تغییر منطق از نظر زمانی گرانتر است.
یافتن یک تعادل خوب می تواند به ارتقای کیفیت نرم افزار شما کمک کند، با حداقل تاثیر منفی روی بهره وری و سرعت شما
تست دکمه افزایش
برای آزمایش که increment
دکمه همانطور که باید کار می کند، یعنی برای افزایش count
هر بار که روی آن کلیک می شود یک مقدار، ابتدا باید به آن دسترسی داشته باشیم increment
دکمه ، سپس ما یک جدید را تعریف می کنیم it()
روش برای همان
از آنجایی که مقدار دکمه پویا نیست، یعنی همیشه مقدار آن را خواهد داشت Increment
در داخل آن، ما از getByRole()
روش به جای getByTestId()
برای پرس و جو از DOM.
هنگام استفاده از
getByRole()
روش ، یک نقش یک عنصر HTML را توصیف می کند.
همچنین باید یک شی را وارد کنیم تا مشخص کنیم که کدام دکمه را میخواهیم آزمایش کنیم، زیرا ممکن است هنگام رندر شدن DOM دکمههای زیادی وجود داشته باشد. در شیء، a را تنظیم می کنیم name
با مقداری که باید همان متن باشد روی دکمه افزایش
کار بعدی شبیه سازی یک رویداد کلیک با استفاده از fireEvent()
روشی که باعث میشود رویدادهایی که اقدامات کاربر را در حین آزمایش شبیهسازی میکنند، اجرا کنند.
ابتدا یک تست می نویسیم تا ببینیم آیا مقدار شمارش از مقدار اولیه آن 0 1 افزایش می یابد یا خیر:
// Counter.test.js
import { fireEvent, render, screen } from "@testing-library/react";
import Counter from "./Counter";
describe(Counter, () => {
it("counter displays correct initial count", () => {
render(<Counter initialCount={0} />);
expect(Number(screen.getByTestId("count").textContent)).toEqual(0);
});
it("count should increment by 1 if increment button is clicked", () => {
render(<Counter initialCount={0} />);
fireEvent.click(screen.getByRole("button", { name: "Increment" }));
let countValue = Number(screen.getByTestId("count").textContent);
expect(countValue).toEqual(1);
});
});
این نتیجه در:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (79 ms)
√ count should increment by 1 if increment button is clicked (66 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.405 s
Ran all test suites related to changed files.
سپس ، ما همچنین می توانیم یک تست بنویسیم تا بررسی کنیم count
مقدار 0 قبل از کلیک روی دکمه با تعریف دو بود expect()
روشها – یکی قبل از فعال شدن رویداد کلیک و دیگری بعد از فعال شدن رویداد کلیک:
// Counter.test.js
it("count should increment by 1 if increment button is clicked", () => {
render(<Counter initialCount={0} />);
let countValue1 = Number(screen.getByTestId("count").textContent);
expect(countValue1).toEqual(0);
fireEvent.click(screen.getByRole("button", { name: "Increment" }));
let countValue2 = Number(screen.getByTestId("count").textContent);
expect(countValue2).toEqual(1);
});
تست ها همچنان گذراندند:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (82 ms)
√ count should increment by 1 if increment button is clicked (60 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.388 s
Ran all test suites related to changed files.
آزمایش دکمه کاهش
به همان روشی که آزمون را برای Increment
دکمه ، ما آزمون را برای Decrement
دکمه مانند این:
// Counter.test.js
it("count should decrement by 1 if decrement button is clicked", () => {
render(<Counter initialCount={0} />);
fireEvent.click(screen.getByRole("button", { name: "Decrement" }));
let countValue = Number(screen.getByTestId("count").textContent);
expect(countValue).toEqual(-1);
});
این نتیجه در:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (79 ms)
√ count should increment by 1 if increment button is clicked (73 ms)
√ count should decrement by 1 if decrement button is clicked (21 ms)
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 2.346 s
Ran all test suites related to changed files.
دکمه راه اندازی مجدد را آزمایش کنید
شبیه به Increment
و Decrement
دکمه ها ، ما آزمون را برای Restart
دکمه مانند این:
// Counter.test.js
it("count should reset to 0 if restart button is clicked", () => {
render(<Counter initialCount={50} />);
fireEvent.click(screen.getByRole("button", { name: "Restart" }));
let countValue = Number(screen.getByTestId("count").textContent);
expect(countValue).toEqual(0);
});
برای آزمایش، مقدار اولیه روی 50 تنظیم شد (مقدار دلخواه) و وقتی تست اجرا شد، هر چهار تست با موفقیت انجام می شود:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (81 ms)
√ count should increment by 1 if increment button is clicked (57 ms)
√ count should decrement by 1 if decrement button is clicked (21 ms)
√ count should reset to 0 if restart button is clicked (16 ms)
Test Suites: 1 passed, 1 total
Tests: 4 passed, 4 total
Snapshots: 0 total
Time: 2.583 s
Ran all test suites related to changed files.
آزمایش دکمه علامت سوئیچ
تست معکوس کردن علامت را نیز می نویسیم روی را count
ارزش با تنظیم مقدار count
تا 50 در فایل تست. سپس به این دقت کنید که چه علامتی قبل و بعد از اجرای یک رویداد کلیک توسط دکمه اجرا می شود:
// Counter.test.js
it("count invert signs if switch signs button is clicked", () => {
render(<Counter initialCount={50} />);
let countValue1 = Number(screen.getByTestId("count").textContent);
expect(countValue1).toEqual(50);
fireEvent.click(screen.getByRole("button", { name: "Switch signs" }));
let countValue2 = Number(screen.getByTestId("count").textContent);
expect(countValue2).toEqual(-50);
});
این نتیجه در:
$ yarn test
PASS src/Counter.test.js
Counter
√ counter displays correct initial count (91 ms)
√ count should increment by 1 if increment button is clicked (72 ms)
√ count should decrement by 1 if increment button is clicked (21 ms)
√ count should reset to 0 if restart button is clicked (19 ms)
√ count invert signs if switch signs button is clicked (14 ms)
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
Snapshots: 0 total
Time: 3.104 s
Ran all test suites related to changed files.
ووش! همه آزمایشات برای برنامه پیشخوان ما با موفقیت سپری شده است.
نوشتن تستها سخت نیست – ما به طور موثر موارد استفاده یک ویژگی را شبیهسازی میکنیم تا مطمئن شویم که در صورت استفاده بهصورت مورد نظر و ناخواسته خراب نمیشود. آیا کسی ارزشی خارج از محدوده ارائه کرده است؟ فرمت اشتباه؟ برنامه باید به جای شکست مشکل را حل کند.
به طور کلی، یک نقطه شروع خوب برای آزمایش این است:
- برای رفتار مورد نظر آزمایش کنید (هر ویژگیهایی که دارید)
- تست تمام جنبه های رفتار ناخواسته (ورودی های اشتباه، مانند فرمت های پشتیبانی نشده، کران ها، و غیره)
- آزمایش عددی (اگر ویژگی شما مقادیر عددی قابل تأیید را تولید می کند، نتیجه را با دست محاسبه کنید و بررسی کنید که آیا خروجی درست را برمی گرداند)
بهترین روش ها برای تست واحد
-
تست ها باید قطعی باشند: اجرای همین تست ها روی یک جزء یکسان چندین بار باید هر بار نتایج یکسانی را به همراه داشته باشد. باید مطمئن شوید که عکسهای فوری تولید شده شما حاوی دادههای خاص پلتفرم یا سایر دادههای غیر قطعی نیست.
-
از انجام آزمایشات غیر ضروری خودداری کنید: تست های خوب با انتظارات غیر ضروری یا موارد آزمایش همراه نیستند.
با نگاهی به تست های زیر می توانیم درک بهتری پیدا کنیم:
test('the success modal is visible', () => {});
test('the success modal has a success message', () => {});
اگر بدانیم که پیام موفقیت در مدال موفقیت قابل مشاهده است، به این معنی است که خود مدال موفقیت نیز قابل مشاهده است. بنابراین در این صورت میتوانیم با خیال راحت اولین آزمایش را حذف کنیم و فقط آزمایش دوم را انجام دهیم یا آنها را با هم ترکیب کنیم. انجام آزمایشهای زیاد میتواند احساس امنیت کاذبی را در صورت زیاد بودن آنها ایجاد کند.
-
از افشای منطق داخلی خودداری کنید: اگر تست شما عملی را انجام می دهد که کاربر شما انجام نمی دهد (مانند آزمایش یک روش داخلی که در معرض دید کاربر نیست)، به احتمال زیاد جزئیات پیاده سازی را آزمایش می کنید. شما می توانید در پایان یک عملکرد خصوصی را صرفاً برای آزمایش مؤلفه خود قرار دهید. این یک بوی رمز است که باید از آن اجتناب کرد. در عوض ، پایگاه کد خود را مجدداً بازسازی کنید تا عملکرد خصوصی بدون آنکه به صورت عمومی در معرض آن قرار گیرد ، قابل آزمایش باشد.
-
از آزمایش جزئیات پیاده سازی خودداری کنید: اگر برنامه ما افزایش یابد
x
وy
– چهx
تا زمانی که نتیجه یکسان باشد ، ابتدا افزایش می یابد یا احتمالاً هیچ اهمیتی ندارد. شما باید بتوانید همیشه جزئیات پیاده سازی را تغییر دهید، تغییر دهید و در غیر این صورت به روز کنید بدون شکستن تست هادر غیر این صورت، آزمایشها با افزایش هزینه بازسازی و بهینهسازی، انباشت بدهی فناوری را تسریع میکنند. -
منطق کسب و کار را به جای اجزای UI در کارکردهای خالص قرار دهید.
نتیجه
این راهنما در درجه اول در مورد تست واحد است. با این حال، مهم این بود که ما ابتدا همه چیزهایی را که شامل تست میشود، از جمله معنای آن، رویکردهای تست، انواع تست، و مزایا و معایب آن را درک کرده و قدردانی کنیم.
یادآوری این نکته بسیار مهم است که چرا در هنگام نوشتن آنها تست می نویسید. به طور معمول ، هدف از نوشتن آزمون صرفه جویی در وقت است. اگر پروژه ای که در حال کار هستید ، تست سود سهام را پرداخت می کند روی پایدار است و برای مدت طولانی توسعه خواهد یافت. با این کار ، به راحتی می توان گفت که آزمایش یک برنامه ممکن است ارزش آن را نداشته باشد ، اگر در زمان توسعه شما صرفه جویی نمی کند. مهمتر از همه ، آزمایش های خوب برای حفظ و ارائه اعتماد به نفس هنگام تغییر کد شما ساده است.
ما همچنین یاد گرفتیم که چگونه DOM را هنگام آزمایش برنامه های React با استفاده از getByTestId()
روش. برای تعریف کانتینرها و عناصر پرس و جو با متن پویا بسیار مفید است، اما نباید درخواست پیش فرض شما باشد. به جای استفاده از getByTestId()
روش فوراً، ابتدا یکی از اینها را امتحان کنید:
getByRole()
– این یک عنصر را پرس و جو می کند و در عین حال با نقش و متن صحیح در دسترس استgetByLabelText()
– این یک پرس و جو عالی برای تعامل با عناصر فرم است، همچنین بررسی می کند که برچسب های ما از طریق ویژگی های for و id به درستی به ورودی های ما مرتبط هستند.getByText()
– هنگامی که هیچ یک از دو سؤال قبلی در دسترس نیست ،getByText()
روش در دسترسی به عناصر مبتنی بر مفید خواهد بود روی متنی که برای کاربر قابل مشاهده استgetByPlaceholderText()
: این پرس و جو به یک شناسه آزمایشی ترجیح داده می شود، زمانی که تنها چیزی که باید برای یک عنصر پرس و جو کنید یک مکان نگهدار است.
تست زمین بازی یک ابزار عالی برای تعیین سریع روش عملکرد یک پرس و جو است.
ما امیدواریم که این راهنما برای شما مفید باشد! با استفاده از این میتوانید به مخزن این راهنما دسترسی داشته باشید و با همه چیزهایی که در آن است بازی کنید ارتباط دادن روی GitHub.
منتشر شده در 1403-01-05 15:10:04