تست نویسی در ری اکت برعکس اسم وحشتناکی که داره و تصور اشتباهی که درمورد سخت بودنش وجود داره، خیلی خیلی آسونه! هرجا بحث تست نویسی در React میشه، همه فکر میکنن این یه مبحث خیلی سخت و پیچیدس!
دقیقا به همین دلیل تصمیم به انتشار این مقاله گرفتیم تا تست نویسی در ریکت رو به ساده ترین شکل ممکن بررسی کنیم 🙂
اگه React Developer هستی و چیزی درمورد تست نویسی در React نمیدونی و میخوای یه Level-Up خفن داشته باشی، این مقاله رو مطالعه کن چون به ساده ترین شکل ممکن تست نویسی در ری اکت رو آموزش دادیم 🙂
با فِرانت اِندی همراه باشید 🙂
زمانیکه یک اپیکیشن میسازیم، اپیکیشن ما از صدها یا هزاران بخش، تابع و کلاس مختلف تشکیل میشه.
ما باید به یک روشی مطمئن بشیم که تمامی این بخش ها دارن بخوبی کار میکنن و هیچ مشکلی ندارن.
این روش، تست نویسی هست 🙂
تست نویسی به ما اجازه میده عملکرد اجزای مختلف اپیکیشن خودمون رو تست کنیم و اطمینان حاصل کنیم که همه چیز داره درست کار میکنه.
در حقیقت ما باید برای هر جز اپیکیشن خودمون یک تست واحد ( unit test ) بنویسیم تا مطمئن بشیم اون بخش داره درست کار میکنه ( مثلا برای هر تابع )
تست نویسی باعث میشه مطمئن بشیم تیکه کد های ما همونطور که ازشون انتظار داریم، کار میکنن.
درکل تست هایی که مینویسیم باید موارد زیر رو پوشش بدن :
تست نویسی در React خیلی خوب و ضروریه اما نباید هرچیزی رو تست کرد!
بریم ببینیم تست نویسی در ری اکت تو چه مواردی کاربرد نداره ..
درواقع نیازی نیست عملکرد واقعی یک تابع رو چک کنیم فقط کافیه اون رو بصورت کلی تست کنیم تا از عملکرد صحیح کلی اون تابع اطمینان حاصل کنیم.
اگه از کتابخانه های خارجی و شخص ثالث استفاده میکنید نیازی نیست که شما عملکرد اونارو تست کنید! درحقیقت توسعه دهنده های اون کتابخانه، باید اون کتابخانه رو تست کنن.
مثلا اگه از کتابخانه Axios در ری اکت استفاده میکنید، نیازی نیست برای این کتابخانه تست نویسی ری اکت انجام بدید.
اگه درک این موارد براتون سخته، اصلا نگران نباشید چون تو ادامه با ذکر مثال این موارد رو بررسی میکنیم 🙂
تست نویسی در ری اکت یکی از اون مباحث پیشرفته و خیلی مهم هست که کمتر کسی بهش توجه میکنه!
شاید یکم زمانبر باشه، اما تست نویسی در ریکت باعث میشه از عملکرد صحیح اپیکیشن خودمون اطمینان حاصل کنیم.
تست نویسی در React شامل موارد زیر میشه :
خب دیگه تئوری صحبت کردن کافیه 🙂 بریم یکم کد ببینیم.
برای بررسی بهتر تست نویسی در ریکت ، ما میخوایم یک پروژه React ایجاد کنیم.
برای اینکار ، به کمک CRA یا همون create-react-app یک پروژه ری اکتی میسازیم. سپس از کتابخانه Jest در ری اکت کمک میگیریم.
همچنین به کتابخانه react testing library نیاز داریم.
نکته ای که وجود داره این هست که با نصب React ، هر دو این کتابخانه ها برای ما نصب میشن.
اگه به فایل package.json پروژه خودمون مراجعه کنیم، میبینیم که هر 2 پکیج مورد نیاز برای تست نویسی در React بصورت پیشفرض برای ما نصب شده :
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
این مورد تو خط 2 و 3 مشخصه.
مورد بعدی که باید ازش مطمئن بشیم، وجود 2 خط کد زیر در فایل setupTests.js هست :
import '@testing-library/jest-dom';
import '@testing-library/jest-dom/extend-expect';
اگه 2 خط کد بالا، تو فایل setupTests.js وجود داشت عالیه. حالا باید بخش scripts در فایل package.json رو بصورت زیر تغییر بدیم ( اضافه کردن کامند تست در ری اکت ) :
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --watchAll --coverage",
"eject": "react-scripts eject"
},
خط 4 تیکه کد بالا باعث میشه تست ما درحالت اجرا نمایش داده بشه و بصورت کامل پوشش داده بشه.
برای تغییر پوشش دادن تست توی Jest میتونیم کد زیر رو اضافه کنیم : ( برای پوشش 70% )
"jest": {
"coverageThreshold": {
"global": {
"lines": 70
}
}
}
خب دیگه تنظیمات Jest و تست نویسی در ری اکت تموم شد 🙂 بریم که یه تست بنویسیم . . .
فرض کنیم کامپوننت زیر رو داریم و میخوایم براش تست نویسی انجام بدیم:
const FirstTest = () => {
return (
<div>
<h2> First test </h2>
</div>
)
}
بنظر شما برای کامپوننت بالا چه تستی باید بنویسیم ؟!
تو کامپوننت بالا ما میتونیم این مورد رو تست کنیم که آیا اِلِمان h2 رندر میشه یا خیر! ( تو خط 4 )
حالا این سوال پیش میاد که برای اِلِمان h2 چطور تست نویسی انجام بدیم ؟
ما میتونیم تست نویسی در ریکت رو در پوشه –tests– داخل پوشه src قرار بدیم.
فایل تست ما باید پسورد زیر رو داشته باشه :
.test.js/jsx
درواقع اجرا کننده تست ( test runner ) فقط همین فایل هارو شناسایی و اجرا میکنه.
الان شاید سوال برامون پیش بیاد که یک فایل تست، چه شکلیه ؟
تیکه کد زیر فایل FirstTest.test.jsx هست که بالاتر کامپوننتش رو نوشته بودیم :
import { render, screen } from '@testing-library/react'
import FirstTest from '../components/FirstTest';
test("Example 1 renders successfully", () => {
render(<FirstTest/>);
const element = screen.getByText(/first test/i);
expect(element).toBeInTheDocument();
})
در مرحله اول از متود ()test استفاده کردیم که یک individual test محسوب میشه. این متود 2 آرگومان ورودی از ما میگیره:
آرگومان اول نام تست هست.
آرگومان دوم یک callBack هست.
تو خط شماره 4 از متود test استفاده کردیم.
حالا باید کامپوننتی که قصد تست کردنش رو داریم، به کمک متود render تست کنیم ( در خط 5 )
حالا به کمک آبجکت screen میتونیم یک اِلِمان رو بگیریم. ( تو این مثال ما اِلِمان h2 رو توی خط 7 گرفتیم )
نکته : ما از regex برای گرفتن اِلِمان خودمون استفاده کردیم ( تو خط 7 )
حالا باید یک ادعا بسازیم. ما میخوایم ادعا کنیم که اِلِمان ما توی صفحه render شده.
این ادعا رو توی خط 9 به کمک expect ایجاد کردیم . این ادعا با موفقیت انجام شده ( pass شده )
تو مثال بالا ما فقط این ادعا رو مطرح کردیم که اِلِمان h2 توی صفحه رندر شده، اما میتونیم ادعا های بیشتری هم بکنیم.
بیاید سناریویی رو در نظر بگیریم که داریم از Back-End اطلاعاتی رو دریافت میکنیم و نمایش میدیم :
import React from 'react'
const TestWithMockData = ({data}) => {
return (
<div>
<ul>
{data.map(item => (
<li key={item.id}>
{item.id}
{item.first_name},
{item.last_name},
{item.email}
</li>
))}
</ul>
</div>
)
}
export default TestWithMockData
تو کامپوننت بالا ما داریم یکسری data رو بصورت Props دریافت میکنیم و نمایش میدیم. تست نویسی در چنین شرایطی ( که Props داریم ) مستلزم ساخت مقداری Data تستی ( Mock Data ) هست.
( اگه با Props آشنا نیستید، پیشنهاد میکنم مقاله Props در ریکت رو مطالعه کنید )
این Data ها دقیقا مشابه Data های Back-End هستن :
const mockData = [
{
"id": 1,
"first_name": "Fletcher",
"last_name": "McVanamy",
"email": "mmcvanamy0@e-recht24.de",
"age": 30
},
{
"id": 2,
"first_name": "Clarice",
"last_name": "Harrild",
"email": "charrild1@dion.ne.jp",
}
]
نکته درمورد Mock Data
دیتا های اصلی بک اند شما ممکنه هزاران عدد باشه اما Mock Data شما چند عدد باشه کافیه ( صرفا برای تست میخوایمشون )
خب بریم که تست نویسی در React برای کامپوننت بالایی رو انجام بدیم ..
این تست رو توی تیکه کد زیر میشه دید :
test("List renders successfully", () => {
render(<TestWithMockData data={mockData} />)
expect(screen.getByText(/fletcher/i)).toBeInTheDocument();
})
بیاید کامپوننت بالا رو با سناریوی متفاوتی در نظر بگیریم. تو کامپوننت زیر یک Props به اسم displayUnorderdList داریم که رندر شرطی رو برامون انجام میده.
همچنین برای سن بیشتر از 50 سال، عبارت senior و سن کمتر از 50 عبارت Not Senior رو نمایش میدیم :
import React from 'react'
const TestWithMockData = ({data, displayUnorderedList, handleClick}) => {
return (
<div>
{displayUnorderedList ?
<ul>
{data.map(item => (
<li key={item.id}>
{item.id}
{item.first_name},
{item.last_name},
<a ={() => {
console.log("email link clicked")
handleClick()
}}>{item.email}</a>
{item.age > 50 ? 'Senior' : 'Not senior'}
</li>
))}
</ul>
:
<ol>
{data.map(item => (
<li key={item.id}>
Last name: {item.last_name}
</li>
))}
</ol>
}
</div>
)
}
export default TestWithMockData
ما برای کامپوننت بالا ( TestWithMockData )َ تست نویسی انجام دادیم. پس اگه به کنسول خودمون نگاهی بندازیم با صحنه زیر مواجه میشیم :
اگه به بخش Uncovered نگاهی بندازیم، میبینیم که نوشته خط 9 توسط تست پوشش داده نشده. و تست ما ناموفق بوده چون نتونسته متن fletcher رو پیدا کنه (این متن رو توی تست بهش داده بودیم که پیدا کنه ).
برای اینکه بتونیم تموم بخش کامپوننت رو پوشش بدیم باید بصورت زیر تست بنویسیم :
test("Ordered list renders", () => {
render(<TestWithMockData data={mockData} displayUnorderedList={false} />)
expect(screen.getByText(/McVanamy/i)).toBeInTheDocument()
})
خب حالا تست ما کل کامپوننت رو پوشش میده 🙂
تو تصویر زیر نتیجه رو میشه دید :
البته باتوجه به عکس بالا میشه فهمید که هنوز خط 15 پوشش داده نشده. پس باید Mock Data خودمون رو بصورت زیر تغییر بدیم تا یک سن بیشتر از 50 داشته باشیم :
{
"id": 3,
"first_name": "Amby",
"last_name": "Emmer",
"email": "aemmer2@buzzfeed.com",
"age": 67
}
حالا دیگه تمومه و کل کامپوننت ما تحت پوشش تست ما هست 🙂
لطفا برای مطالعه ادامه مقاله + تیکه کد ها و مثالهای بیشتر روی لینک زیر کلیک کنید :