راهنمای کوچک CI/CD برای توسعه دهندگان Frontend

اگر مدتی کار من را دنبال کرده اید یا مقالات قبلی من را خوانده اید، ممکن است متوجه شده باشید که من دوست دارم ابزارهایی ایجاد کنم که قابلیت اطمینان و مقیاس پذیری پروژه هایی را که روی آنها کار می کنم بهبود می بخشد. سیبه طور مداوم منادغام و سیبه طور مداوم آقایخط لوله elivery، همچنین نامیده می شود CI/CD، یکی از آنهاست.
ساختن چنین خط لوله ای و تا حد امکان خودکار ساختن آن مانند دادن قدرت های فوق العاده به تیم خود است. با استفاده از آن می توانید سازمان خود را قادر به ارائه موارد زیر کنید:
-
کدی که از دستورالعملهای سبک و قالببندی ثابت پیروی میکند
-
نرم افزار قابل اعتماد و همچنین نسخه های بعدی آن برای جلوگیری از رگرسیون تست شده است
-
نسخه های متوالی: انتشار نسخه جدید برای مشتری تا حد امکان آسان است و تیم شما می تواند در کوتاه ترین زمان اصلاحات را به تولید برساند.
-
ویژگیهایی که در صورت کاهش تجربه کاربر به راحتی قابل برگشت هستند
-
هر تغییر محصول آینده را می توان به عنوان یک واحد تغییر مستقل تجسم کرد
-
تا حد امکان از زمان هر توسعه دهنده استفاده کنید. توسعه دهندگان هزینه دارند، و شما نمی خواهید آنها دائما آتش تولید را خاموش کنند. آزمایش و انتشار را به صورت خودکار انجام دهید، تا جایی که ممکن است همه انسان ها را از این فرآیند حذف کنید. تست بیشتر یعنی اشتباهات کمتر یعنی ترس کمتر از تغییر. ترس کمتر از تغییر به معنای آزمایش و نوآوری بیشتر است. اتوماسیون بیشتر به معنای زمان بیشتر برای آزمایش و نوآوری است.
اگر تیم شما از فرآیندهای انتشار پیچیده رنج می برد، در تلاش است تا تولید را در همان روز اصلاح کند، یا به طور قابل اعتماد یک ویژگی جدید را به مشتریان ارائه دهد: این مقاله برای شماست!
در این پست، تمام ابزارهایی که شما و تیمتان برای ایجاد یک محیط توسعه با سرعت بالا، از بین بردن ترس از انتشار، و ایجاد فرآیندها نیاز دارید را در اختیار شما قرار خواهم داد. تا تیم خود را غیرقابل توقف کنید. همانطور که از عنوان نشان می دهد، موارد زیر برای توسعه دهندگان فرانت اند نوشته می شود، زیرا من در این زمینه دانش بیشتری دارم، به خصوص در مورد ابزارها. با این حال، مفاهیم و مراحلی که به تفصیل توضیح خواهم داد نیز میتواند برای توسعهدهندگان باطنی که به دنبال بهبود فرآیند آزمایش و انتشار تیم خود هستند، ارزشمند باشد.
تأثیر اتوماسیون بر تیم، سازمان و کاربران شما
هنگام شروع کار بر روی خط لوله CI/CD جدید یا به دنبال بهبود خط لوله موجود، مهم است که تلاش ها را در جایی متمرکز کنید که می خواهید بیشترین تأثیر مثبت را داشته باشید:
-
تست واحد، قالب بندی، پرده زدن و تست یکپارچه سازی: عمدتا بر توسعه دهندگان تیم شما تأثیر می گذارد. داشتن عادت خوب به نوشتن تست های واحد و حفظ یک سبک کد ثابت می تواند سرعت یک تیم را افزایش دهد. اینا همونایی هستن که زنگ زدم سریع دویدن سریع به شکست: اینها را می توان به سرعت اجرا کرد تا هر گونه مشکل در پایگاه کد شناسایی شود و به عنوان اولین خط دفاع در برابر اشکالات عمل کند.
-
آزمایش انتها به انتها، انتشار خودکار و پیش نمایش شعبه در سطح بین عملکردی یا سازمانی تأثیرگذارتر هستند. تست انتها به انتها به عنوان مثال فعال خواهد شد تیم فرانت اند و تیم باطن شما برای آزمایش برخی از مسیرهای حیاتی کاربر. نسخه های خودکار مطمئن شوید که همه چیز با کمترین اصطکاک ممکن آزاد می شود و کل سازمان شما می تواند در سریع ترین زمان ممکن به درخواست مشتری پاسخ دهد. در نهایت نماهای شاخه فعال کردن تیم جلویی و تیم QA شما بررسی کار قبل از شروع تولید. هر ویژگی یا پچ آینده را می توان در سرویس خود میزبانی کرد و به طور مستقل آزمایش کرد.
-
پرچم های ویژگی و تست دسترسی بیشتر مشتری مدار هستند آنها تجربه بهتر و فراگیرتری را برای همه کاربران شما تضمین می کنند و همچنین از وقفه در سرویس هنگام ارائه ویژگی های جدید جلوگیری می کنند.
زیر یک خط لوله نسبتا کامل CI/CD و تمام مراحل مختلف آن را نشان می دهد. من همچنین این خط لوله را به 3 قسمت تقسیم کرده ام که نشان می دهد کدام یک از تیم، سازمان و کاربر نهایی هر مرحله از خط لوله بیشترین تأثیر مثبت را دارد:
تست های پرز، قالب بندی و واحد
این سه عنصر بلوک های سازنده تیم شما برای ارائه سریعتر نرم افزار قابل اعتمادتر هستند.
پرده زدن و قالب بندی
پردهبندی و قالببندی برای حفظ پایگاه کد شما ضروری است سازگار و تمیز کردن. هر عضو تیم باید از قوانین و قراردادهای یکسانی برای نوشتن کد پیروی کند. سازگاری در خود پایگاه کد ضروری است:
-
شما نمی خواهید هنگام ورود به یک عضو تیم جدید، در مورد نحوه نوشتن یک قطعه کد در برنامه خود سردرگمی ایجاد کنید.
-
شما نمی خواهید چندین روش را برای انجام یک کار مستند کنید
ابزارهایی که استفاده میکنم
برای این مرحله، من می خواهم ابزارهایم سریع و قابل اعتماد باشند. فقط باید **چند ثانیه** طول بکشد تا پایگاه کد من پرده و فرمت شود. من به عنوان یک مهندس پیشتاز استفاده می کنم
-
ESlint for linting دارای مجموعه ای از قوانین برای نوشتن جاوا اسکریپت صحیح است و این قوانین را می توان با توجه به نیازهای تیم شما سفارشی کرد. همچنین، اگر به چیز خاصی نیاز دارید، میتوانید قوانین ESLint خود را ایجاد کنید، من در اینجا در مورد آن نوشتم، این تمرین جالبی است که شامل درخت نحو انتزاعی (AST) است.
-
زیباتر برای قالب بندی در چند سال گذشته به ابزار قالببندی واقعی برای توسعهدهندگان جاوا اسکریپت تبدیل شده است. من آن را در پروژه و ویرایشگر خود به گونه ای تنظیم کردم که ذخیره یک فایل به طور خودکار آن را برای من فرمت می کند.
همانطور که در بالا گفتیم، این مرحله باید بسیار سریع باشد. آنقدر سریع که میتوانید این مرحله را بهعنوان یک قلاب پیشفرض (یک اسکریپت دلخواه که در هر commit اجرا میشود. من دوست دارم استفاده کنم) اجرا کنید. هاسکی آنها را تنظیم کنید) زیرا از فرمت و خواندن کد اطمینان حاصل می کند قبل از بررسی آن برعهده هم تیمی های شماست.
تست های واحد
همانطور که قبلاً گفتم، من دوست دارم این تست ها را بنامم سریع اجرا شود، **به سرعت از کار می افتد. ** اجرای آنها نباید زیاد طول بکشد و بسته به مقیاس پروژه شما باید خطاها یا اشکالات را در چند ثانیه یا حتی چند دقیقه نشان دهند.
هدف در اینجا این است که هر بخش از برنامه خود را به عنوان “واحد” یا اجزای جدا شده آزمایش کنید. به عنوان مثال، در یک پروژه React، این تست ها ممکن است شامل موارد زیر باشد:
-
اجزاء: من دوست دارم از تست های واحد استفاده کنم تا مطمئن شوم که اجزای من رفتار و عملکرد درستی دارند که انتظار می رود توسط خودشان، یعنی ** در ترکیب با سایر اجزا یا نماهای برنامه من ** نیست.
-
کاهش دهنده ها / وضعیت / اقدامات: تستهای واحد میتوانند به تأیید اینکه وضعیت شما به روشی خاص برای یک اقدام معین بهروزرسانی شده است کمک کند. کاهنده ها توابع خالص هستند (یعنی توابعی که همیشه خروجی یکسانی را برای یک ورودی مشخص برمی گرداند)
-
توابع مفید: ما در پروژههای خود کمکهای زیادی میسازیم یا بسیاری از توابع را انتزاعی میکنیم: اینها نمونههای کاملی از چیزهایی هستند که ممکن است بخواهید برای آنها تستهای واحد بنویسید.
من تست های واحد را بسیار دوست دارم زیرا آنها به عنوان یک بررسی استحکام در پروژه شما عمل می کنند تا مطمئن شوید که قطعات جداگانه آن همانطور که در نظر گرفته شده است کار می کنند. در طول زمان، به روشی بسیار کارآمد (سریع، قابل اعتماد).
ابزارهایی که استفاده میکنم
به عنوان توسعه دهندگان فرانت اند احتمالا نام آنها را شنیده اید یک شوخی. این محبوب ترین چارچوب تست جاوا اسکریپت است و چندین سال است که وجود داشته است. Jest ابزار آزمایشی است که من همیشه ابتدا در پروژه های جاوا اسکریپت خود نصب می کنم. به عنوان مثال، برای اجرای آزمایشها روی برنامههای React خود، از آن در ترکیب با:
-
@testing-library/react : اگر می خواهید تست های قابل نگهداری را در طول زمان بدون نگرانی در مورد جزئیات پیاده سازی بنویسید. من عمدتاً از آن برای رندر کردن اجزای جداگانه و آزمایش آنها استفاده می کنم.
-
@testing-library/jest-dom: این بسته تطبیق عنصر DOM اضافی را به شما می دهد تا نوشتن و خواندن تست های شما را آسان تر کند.
نگهدارندگان @testing-library بستههای بسیار دیگری را نیز ارائه کردهاند که به شما کمک میکنند برنامه خود را مستقل از چارچوب (Svelte، VueJS و غیره) آزمایش کنید.
در زیر قطعههای کدی را مشاهده خواهید کرد که مجموعههای آزمایشی را نشان میدهد که به منظور نشان دادن نحوه نوشتن تستها در موقعیتهای مختلف است.
در این یکی، من React ساده را آزمایش می کنم Button با استفاده از یک جزء @testing-library/react و شوخی
نمونه مجموعه تست واحد برای یک جزء Button با استفاده از @testing-library/react
2
import React from 'react';4
const Button = (props) => {14
button {...rest} onClick={() => onClick()} disabled={loading || disabled}>15
{loading ? 'Loading ...' : children}24
import React from 'react';25
import { render, screen } from '@testing-library/react';26
import userEvent from '@testing-library/user-event';27
import '@testing-library/jest-dom/extend-expect';28
import Button from './';30
describe('Button Component', () => {31
it('Renders the Button as expected and clicking on it calls the function passed in the onClick prop', () => {32
const onClickMock = jest.fn();33
const { container, debug } = render(34
Button name="test-btn" onClick={onClickMock}>39
expect(screen.getByRole('button')).toBeInTheDocument();40
expect(screen.getByRole('button')).toHaveTextContent('Test');41
expect(screen.getByRole('button')).not.toHaveAttribute('disabled');42
userEvent.click(screen.getByRole('button'));43
expect(onClickMock).toHaveBeenCalled();46
it('Renders the Button with loading set to true and clicking on it does not call the function passed in the onClick prop', () => {47
const onClickMock = jest.fn();48
const { container, debug } = render(49
Button name="test-btn" loading onClick={onClickMock}>54
expect(screen.getByRole('button')).toBeInTheDocument();55
expect(screen.getByRole('button')).toHaveTextContent('Loading ...');56
expect(screen.getByRole('button')).toHaveAttribute('disabled');57
userEvent.click(screen.getByRole('button'));58
expect(onClickMock).not.toHaveBeenCalled();61
it('Renders the Button with disabled set to true and clicking on it does not call the function passed in the onClick prop', () => {62
const onClickMock = jest.fn();63
const { container, debug } = render(64
Button name="test-btn" disabled onClick={onClickMock}>69
expect(screen.getByRole('button')).toBeInTheDocument();70
expect(screen.getByRole('button')).toHaveTextContent('Test');71
expect(screen.getByRole('button')).toHaveAttribute('disabled');72
userEvent.click(screen.getByRole('button'));73
expect(onClickMock).not.toHaveBeenCalled();
برای این قطعه کد، من روی آزمایش یک تابع کاهنده تمرکز می کنم که می تواند دو نوع عمل مختلف را انجام دهد. من عاشق تست کردن کاهنده ها هستم، زیرا به عنوان توابع خالص، خروجی های قابل پیش بینی بدون توجه به پیچیدگی دارند، بنابراین نوشتن تست برای آنها همیشه یک برد آسان برای تیم شما است.
نمونه ای از تست کاهنده/واحد تابع
2
const initialState = {};4
const reducer = (state = initialState, action) => {7
const { payload } = action;8
const items = payload.reduce((accumulator, currentItem) => {9
accumulator[currentItem.id] = currentItem;12
return { ...state, ...items };23
export default reducer;27
import reducer from './reducer';29
describe('Reducer', () => {30
it('Handles the FETCH_POST action as expected when the initial state is an empty object', () => {43
title: 'Title Test 2',49
const initialState = {};51
expect(reducer(initialState, action)).toEqual({52
1: { body: 'Test', id: 1, title: 'Title Test', userId: 1 },53
2: { body: 'Test2', id: 2, title: 'Title Test 2', userId: 1 },57
it('Handles the FETCH_POST action as expected when the initial state is an empty object', () => {70
title: 'Title Test 2',76
const initialState = {80
title: 'Title Test 3',85
expect(reducer(initialState, action)).toEqual({86
3: { body: 'Test', id: 3, title: 'Title Test 3', userId: 2 },87
1: { body: 'Test', id: 1, title: 'Title Test', userId: 1 },88
2: { body: 'Test2', id: 2, title: 'Title Test 2', userId: 1 },92
it('Handles the CLEAR_POSTS action as expected', () => {97
const initialState = {101
title: 'Title Test 3',106
expect(reducer(initialState, action)).toEqual({});
ادغام و تست سرتاسر
من این بخش را هم به یکپارچه سازی و هم به آزمایش انتها به پایان اختصاص می دهم زیرا گاهی اوقات می بینم که این دو نوع آزمایش به جای هم استفاده می شوند و فکر می کنم دانستن تفاوت های ظریف مهم است.
تست های یکپارچه سازی
این احتمالاً جایی است که باید بیشترین تلاش خود را هنگام نوشتن تست ها متمرکز کنید.
چرا باشه وقتی تلاش لازم برای نوشتن تستها، زمان لازم برای اجرای آنها و سطح اطمینانی که به تیم شما بازمیگرداند را در نظر میگیرید: تستهای ادغام به سادگی بهترین هستند.. تستهای واحد سطح پایینی از اطمینان را به شما میدهند اما سریع اجرا میشوند، در حالی که تستهای پایانی به کندی اجرا میشوند (گاهی اوقات در برخی از برنامههای بزرگ بیش از یک ساعت طول میکشد) و برای اجرا به زیرساختهای گران قیمت نیاز دارند، اما بالاترین سطح اطمینان ممکن را به شما میدهند. با این حال، نوشتن تستهای ادغام آسانتر از تستهای e2e است و به شما کمک میکند تا رفتارهای پیچیدهتری را نسبت به تستهای واحد تایید کنید، همه در مدت زمان نسبتاً کوتاهی.
اگر میخواهید دلیل آن را با جزئیات بدانید، به شما توصیه میکنم کتاب Kent C Dodd’s را بخوانید تست ها را بنویسید پست وبلاگ
در حالی که تستهای واحد به آزمایش بخشهایی از پروژه شما به صورت مجزا کمک میکنند، تستهای یکپارچهسازی به تأیید اینکه مجموعه کاملی از ماژولها مطابق انتظار با هم کار میکنند کمک میکند. آنها همچنین به شما اجازه می دهند تا جریان های کاربر کامل و تمام مسیرهای مختلفی را که می توانند طی کنند (وضعیت خطا، وضعیت بارگیری، وضعیت موفقیت) آزمایش کنید.
با تستهای یکپارچهسازی، من دوست دارم گروههایی از اجزا را آزمایش کنم، عملکردهایی مانند:
-
ناوبری: آیا کلیک کردن روی آیتم منوی تنظیمات سفارشی نمای مورد انتظار را بارگیری می کند؟
-
فرم ها: فرم را به تمامی روش های ممکن (معتبر و نامعتبر، با و بدون فیلد اختیاری) تکمیل کنید. آزمایش کنید که آیا پیام های خطای مورد انتظار زمانی که نامعتبر هستند نمایش داده می شوند یا خیر. اطمینان حاصل کنید که کلیک کردن بر روی ارسال، در صورت اعتبار، محموله صحیح را ارسال می کند. فرمی مانند این میتواند از اجزاء، کاهندهها و توابع کمکی تشکیل شده باشد که به صورت جداگانه در مرحله آزمایش واحد آزمایش کردیم. در اینجا، ما آنها را آزمایش می کنیم که کاملاً در یک زمینه خاص کار کنند.
-
**نماها **بسته به داده های خارجی: نمای لیست خود را که برخی از داده ها را با پاسخ های نادرست API مختلف بازیابی می کند آزمایش کنید: آیا در صورت عدم وجود داده، وضعیت خالی صحیح را نشان می دهد؟ اگر API شما خطایی را برگرداند، دکمه فیلتر فعال است؟ در صورت موفقیت آمیز بودن استخراج، اعلان را نشان می دهد؟
من می توانم با مثال های مختلف ادامه دهم، اما این ها تقریباً موارد استفاده اصلی هستند که من معمولاً هنگام نوشتن تست های یکپارچه سازی روی آنها تمرکز می کنم. من سعی می کنم تمام مسیرهای ممکن را که یک گروه مؤلفه، فرم یا نما می تواند طی کند تأیید کنم.
ابزارهایی که استفاده میکنم
وقتی نوبت به تست ادغام می رسد، من بین استفاده از دو ابزار مختلف، گاهی اوقات در یک پروژه، دچار سردرگمی هستم.
-
یک شوخی: شما می توانید تست های یکپارچه سازی بسیار پیشرفته را با Jest بنویسید،
@testing-library/reactو تمام ابزارهای جالبی که قبلا ذکر کردیم. من اخیراً شروع به استفاده از msw برای تمسخر یک API کردهام که نماهایی که آزمایش میکنم به آنها متفاوت است. -
سرو: با روشی جذاب برای نوشتن فیکسچرها و تمسخر کردن نقاط پایانی API و در نتیجه اجرای برخی از تستهای ادغام ارائه میشود. من عمدتاً از آن برای بررسی برخی رفتارهای مرتبط با مرورگر استفاده میکنم، مانند: آیا پارامترهای درخواست صحیح به URL ارسال میشوند؟ آیا می توانم با افزودن این مجموعه از پارامترها به URL یک نما را در یک وضعیت خاص بارگیری کنم؟ آیا مجموعه خاصی از مقادیر در ذخیره سازی محلی تنظیم شده است یا خیر؟
یک نمونه برنامه React که پست ها را بازیابی می کند و حالت های مختلف را مدیریت می کند
1
import React from 'react';2
import Button from './Button';3
import reducer from './reducer/reducer';6
const [shouldFetch, setShouldFetch] = React.useState(false);7
const [error, setError] = React.useState(null);8
const [posts, dispatch] = React.useReducer(reducer, {});10
React.useEffect(() => {12
fetch('https://jsonplaceholder.typicode.com/posts')13
.then((response) => response.json())19
setShouldFetch(false);21
.catch(() => setError({ message: 'Error :(' }));26
return div data-testid="error">{error.message}/div>;31
{Object.values(posts).length > 0 ? (32
ul data-testid="posts">33
{Object.values(posts).map((post) => (34
li key={post.id} data-testid="post">40
div data-testid="empty">No Posts/div>42
Button onClick={() => setShouldFetch(true)} loading={shouldFetch}>
شاید متوجه شده باشید که این برنامه از همین روش استفاده می کند Button جزء و reducer ما قبلا به صورت مجزا (یعنی واحد آزمایش شده) آزمایش کردیم. همانطور که در بالا گفته شد، هدف از تست های یکپارچه سازی تایید این است که آیا این واحدها می توانند در یک مورد خاص با هم کار کنند یا خیر. در زیر نمونهای از یک آزمون یکپارچهسازی معمولی است که برای برنامهای مانند آنچه در بالا نشان داده شده است مینویسم. من نتایج مختلف ممکن را برای این لیست از پست ها آزمایش می کنم:
-
لیست پست همانطور که انتظار می رود بارگیری می شود و به درستی نمایش داده می شود
-
لیست پست ها در حال بارگیری است اما خالی است
-
هنگام بازیابی پست ها خطایی رخ می دهد و وضعیت خطای بازگشتی همانطور که انتظار می رود نمایش داده می شود
نمونه ای از مجموعه تست یکپارچه سازی که برای آزمایش مسیرهای ممکن مختلف برای برنامه نمونه می نویسم
1
import React from 'react';2
import { rest } from 'msw';3
import { setupServer } from 'msw/node';4
import { render, fireEvent, waitFor, screen } from '@testing-library/react';5
import userEvent from '@testing-library/user-event';6
import '@testing-library/jest-dom/extend-expect';7
import App from './App';18
const server = setupServer(19
rest.get('https://jsonplaceholder.typicode.com/posts', (req, res, ctx) => {31
title: 'Title Test 2',39
beforeAll(() => server.listen());40
afterEach(() => server.resetHandlers());41
afterAll(() => server.close());43
describe('App', () => {44
it('Renders the app and loads the posts', async () => {47
userEvent.click(screen.getByText('Fetch Posts'));48
expect(screen.getByRole('button')).toHaveTextContent('Loading ...');49
expect(screen.getByRole('button')).toHaveAttribute('disabled');50
await waitFor(() => screen.getByTestId('posts'));52
expect(screen.getAllByTestId('post')).toHaveLength(2);53
expect(screen.getAllByTestId('post')[0]).toHaveTextContent('Title Test');54
expect(screen.getAllByTestId('post')[1]).toHaveTextContent('Title Test 2');56
expect(screen.getByRole('button')).toHaveTextContent('Fetch Posts');57
expect(screen.getByRole('button')).not.toHaveAttribute('disabled');60
it('Renders the app when there are no posts returned', async () => {63
'https://jsonplaceholder.typicode.com/posts',66
return res(ctx.json([]));72
userEvent.click(screen.getByText('Fetch Posts'));73
expect(screen.getByRole('button')).toHaveTextContent('Loading ...');74
expect(screen.getByRole('button')).toHaveAttribute('disabled');75
await waitFor(() => screen.getByTestId('empty'));77
expect(screen.getByText('No Posts')).toBeInTheDocument();80
it('Renders the app when the posts do not load', async () => {83
'https://jsonplaceholder.typicode.com/posts',86
return res(ctx.status(500));92
userEvent.click(screen.getByText('Fetch Posts'));93
expect(screen.getByRole('button')).toHaveTextContent('Loading ...');94
expect(screen.getByRole('button')).toHaveAttribute('disabled');95
await waitFor(() => screen.getByTestId('error'));97
expect(screen.getByText('Error :(')).toBeInTheDocument();
تست انتها به انتها
تستهای انتها به انتها، یا گاهی اوقات e2e نیز نامیده میشوند، مجموعهای از تستهایی هستند که نزدیکترین آزمایشها به آنچه کاربر هنگام استفاده از محصول شما باید تجربه کند، است. در اکثر فریم ورک هایی مانند Selenium یا Cypress، مجموعه تست e2e چیزی بیش از a نیست جریان کاربر اسکریپت شده که کامپیوتر از آن عبور خواهد کرد. علاوه بر این، اکثر این تستها **مستقیماً در یک مرورگر** اجرا میشوند و به شما این فرصت را میدهند تا بررسی کنید که برنامه شما در مرورگرهای مختلفی که ممکن است مشتریان شما از آنها استفاده میکنند، درست کار کند.
تست های انتها به انتها مزایا و معایب زیادی دارند:
جوانب مثبت:
-
آنها “واقعی ترین” مجموعه تست ها هستند: شما تست های خود را با نسخه داخلی برنامه UI خود در یک مرورگر اجرا می کنید.
-
آنها تایید می کنند که آیا شما کل محصول همانطور که انتظار می رود کار می کند، که شامل backend، API، پایگاه های داده ای که ممکن است درگیر باشد و غیره است.
-
آنها می توانند مشکلات تأخیر (زمان بارگذاری طولانی) و شرایط مسابقه را که ممکن است تیم و سازمان شما هنوز به آن پی نبرده باشند، آشکار کنند.
معایب:
-
اجرای آنها کند، پیچیده و پرهزینه است. از امروز، مراحل e2e طولانی ترین مراحل در اکثر خطوط لوله CI/CD من هستند. همچنین نگهداری آنها در طول زمان بسیار دشوار است، زیرا برنامه شما پیچیده تر می شود، آزمایش ها ممکن است تبدیل شوند پوسته پوسته شدن، ممکن است لازم باشد آنها را به طور کامل بازنویسی کنید تا با برخی از عناصر UX جدید سازگار شوند.
-
شما فقط چیزی را تجربه می کنید که من آن را “مسیر شاد” می نامم. به عنوان مثال، هنگامی که یک تست e2e را بر روی فرمی که دادهها را به یک API ارسال میکند، اجرا میکنید، فقط در صورتی میتوانید آزمایش کنید که همه چیز طبق انتظار پیش برود، زیرا آن تست به APIهای خارجی، سرویسهای Backend بستگی دارد که در اینجا مسخره نمیشوند و فرض میشود کار میکنند، در حالی که با تستهای یکپارچهسازی میتوانید حالتهای خالی، حالتهای موفقیت و حالتهای شکست را آزمایش کنید:

ابزارهایی که استفاده میکنم
اگر هنوز تست e2e را در تیم خود اجرا نکرده اید، **Cypress** را به عنوان نقطه شروع به شدت توصیه می کنم. تیم Cypress در دسترس ترین راه را برای نوشتن تست های e2e در چشم من ساخته است و همچنین بهترین اسناد و پشتیبانی جامعه را دارد.
بهجای نمایش چند قطعه کد، میخواهم برخی از نکاتم را که برای نوشتن تستهای e2e استفاده میکنم، با شما به اشتراک بگذارم:
-
هر آزمایشی باید باشد مستقل. برای یک بسته معین با تست A، B، و C، کل بسته شکست میخورد زیرا یک تست ناموفق A میتواند یافتن مشکلات دیگر با تستهای B و C را دشوار کند. من سعی میکنم هر تست را تا حد امکان مستقل نگه دارم، زیرا باعث صرفهجویی در وقت و تلاش من برای رفع اشکال یک تست شکسته میشود.
-
فراخوانی های API را قبل از آزمایش برای ایجاد تمام اشیاء (وظایف، پست ها، …) که برای آزمایش خود نیاز دارید، راه اندازی کنید. برای یک شی در برنامه شما، ممکن است یک جریان “ایجاد”، “خواندن” و “به روز رسانی” داشته باشید، و من می خواهم هر سه را آزمایش کنم. با این حال، اگر به موفقیت آزمون «ایجاد» بستگی داشته باشد، جریان «خواندن» و «بهروزرسانی» نمیتواند مستقل باشد. بنابراین من تمایل به ایجاد دستورات سفارشی برای فراخوانی APIهای مرتبط برای ایجاد اشیاء مورد نیاز قبل از اجرای آزمایش دارم.
-
تمرینهای تست خوب را در تیم خود تشویق کنید، آنها را اغلب اجرا کنید (در قسمت بعدی به آن خواهیم پرداخت)، به محض شکستن آنها را اصلاح کنید، فهرستی از تستهایی را که میخواهید بنویسید جمعآوری کنید، و آنها را اولویتبندی کنید.
-
اگر در حال حاضر 0 تست e2e در پایگاه کد خود دارید و نمی دانید کدام تست را ابتدا بنویسید: با نوشتن تستی شروع کنید که باگ ترین یا ناپایدارترین ویژگی برنامه شما را تایید می کند. این تست واحد تاثیر مثبتی روی محصول شما خواهد داشت فورا. همانطور که قبلا در این پست گفته شد، تاثیر CI/CD و تست های خود را با بهتر کردن محصول نسبت به قبل از نوشتن تست برجسته کنید. سازمان و کاربران شما بیش از حد سپاسگزار خواهند بود.
تست های دسترسی و ممیزی
این آخرین و مهمترین بخش خط لوله CI/CD است. به اندازه کافی اغلب، سختترین هم است، زیرا اطمینان از اینکه پروژه frontend شما 100% در دسترس است، کار آسانی نیست، اما چیزی است. که همه باید برای آن تلاش کنند.
هیچ چیز کارآمدتر از نشستن پشت رایانه و استفاده از برنامه خود با یک صفحه خوان نیست، اما در اینجا چند ابزار وجود دارد که می توانند به عنوان بخشی از خط لوله خودکار CI/CD اجرا شوند که من از آنها برای اجرا استفاده می کنم. رهبری تلاش های دسترسی:
-
Lighthouse CI: این مجموعه ای از ابزارها است که به شما کمک می کند عملکرد، دسترسی، و اینکه آیا برنامه شما از بهترین شیوه ها پیروی می کند یا خیر. من از این ابزار اساسا استفاده می کنم خط را نگه دارید و مطمئن شوید که اوضاع با گذشت زمان بدتر نمی شود. این به شما امکان می دهد “بودجه های عملکرد و در دسترس بودن” و آستانه ایجاد کنید. اگر نتیجه شما کمتر از بودجه هدف باشد، شکست خواهد خورد. این احتمالاً به خودی خود سزاوار یک مقاله کامل است، اما در عین حال میتوانید مستندات آنها را که شامل نمونه گردش کار Github است بررسی کنید و به راحتی آن را در خط لوله CI/CD خود ادغام کنید.
-
Cypress Axe: این بسته در بالای Cypress اجرا می شود و به شما امکان می دهد مجموعه ای از مجموعه های آزمایشی متمرکز بر دسترسی را اجرا کنید. این به من کمک کرد تا برخی از مشکلات دسترسی پیچیدهتر را پیدا کنم که Lighthouse CI از قلم انداخته بود. من سال گذشته یک پست وبلاگی در مورد تبر Cypress نوشتم و از شما دعوت می کنم اگر می خواهید در مورد آن بیشتر بدانید، آن را بررسی کنید.
ابزارهایی که استفاده میکنم
من همچنین از چندین افزونه Chrome برای ردیابی و یافتن مشکلات دسترسی جدید استفاده میکنم:
با این حال، اینها فقط خارج از خط لوله CI/CD من استفاده میشوند، اما من فکر کردم که ممکن است در این زمینه ارزش ذکر کردن را داشته باشند.
اتوماسیون: چه زمانی و چگونه آزمایشهایم را اجرا کنم و آزاد کنم
اکنون که چند واحد، ادغام، تستهای e2e نوشتهایم و ابزارهایی را برای ردیابی مشکلات دسترسی معرفی کردهایم، وقت آن است که در مورد اتوماسیون صحبت کنیم. هدف تیم شما باید تا حد امکان خودکارسازی باشد، از اجرای آزمایشها گرفته تا تجسم استقرار تا استقرار تا تولید. تنها مرحله دستی باقی مانده در خط لوله CI/CD شما باید بررسی کد باشد. اتوماسیون جزء کلیدی هر تیم توسعه با سرعت بالا است.
هر گونه تغییر کد را تأیید کنید
ما در حال حاضر می دانیم که چگونه این تست ها را به صورت محلی اجرا کنیم، اما می خواهیم اطمینان حاصل کنیم که هر زمان که تغییری در پایگاه کد ایجاد شد، این تست ها به طور خودکار اجرا شوند.
من به طور کلی طرفدار انجام این تست ها هستم هر درخواست دانلود. هر تغییری باید قبل از ادغام بدون استثنا در شاخه اصلی آزمایش شود. این راز پایدار ماندن پروژه و بدون اشکال است: آزمایشها تا حد امکان برای هر واحد تغییر اجرا میشوند. برای اینکه هر گونه تغییر کد به شعبه اصلی برسد، باید آزمایشات انجام شود.
من به عنوان ابزار اتوماسیون اصلی خود، از Github CI، Actions و Workflows هم برای پروژههای مرتبط با کاری و هم برای پروژههای شخصی استفاده میکنم و مانند یک جذابیت عمل میکند! بنابراین من عمدتاً در بخش آینده روی آن تمرکز خواهم کرد و برخی از تنظیمات گردش کار Github را به اشتراک میگذارم، زیرا خواندن آنها آسان است و بنابراین برای افرادی که تازه با این دسته از ابزارها آشنا هستند بسیار قابل دسترسی هستند. ممکن است تیم شما از سرویسهای CI/CD دیگری مانند CircleCI، Jenkins یا Google Cloud Build استفاده کند، بنابراین ممکن است لازم باشد در مورد فایلهای پیکربندی واقعی مورد نیاز، کمی تحقیق کنید، اما مفاهیم زیر همچنان در مورد آن سرویسها صدق میکند.
در اینجا نمونه گردش کار Github است که من معمولاً در چندین پروژه از آنها استفاده می کنم. اگر قبلاً یک خط لوله خودکار CI/CD ندارید، میتوانید از این برای شروع سریع و تکرار استفاده کنید، به خوبی با Github PR ادغام میشود:
نمونهای از یک گردش کار Github که تستهای خودکار را روی هر روابط عمومی اجرا میکند
1
name: Linting Formatting Unit and Integration Tests9
validate-code-and-test:15
- name: Checkout Commit16
uses: actions/checkout@v218
ref: ${{ github.event.pull_request.head.sha }}19
- name: Use Node.js ${{ matrix.node }}20
uses: actions/setup-node@v122
node: ${{ matrix.node }}23
- name: Install Dependencies25
yarn install --non-interactive32
- name: Run Unit and Integration tests
نمونهای از یک گردش کاری Github که تستهای e2e را روی هر PR اجرا میکند
1
name: Linting - Formatting - Unit Tests - Integration16
- name: Checkout Commit17
uses: actions/checkout@v219
ref: ${{ github.event.pull_request.head.sha }}20
- name: Use Node.js ${{ matrix.node }}21
uses: actions/setup-node@v123
node: ${{ matrix.node }}24
- name: Install Dependencies26
yarn install --non-interactive32
uses: cypress-io/github-action@v2.2.238
wait-on: 'http://localhost:3000'39
config: video=true,videoUploadOnPasses=false40
- uses: actions/upload-artifact@v1
برخی از منابعی که ممکن است در مورد Github Workflows و Cypress برای شما جالب باشد:
چیز دیگری که من تمایل دارم در هر روابط عمومی قرار دهم این است تجسم اجراها اینها احتمالاً ویژگی مورد علاقه من در کل خط لوله CI/CD هستند: شما از هر PR که از طریق یک نقطه پایانی منحصر به فرد به آن دسترسی دارید، خود استقرار پیدا می کنید. هر استقرار نسخه ای از پروژه frontend شما با یک تغییر خاص است. این نه تنها می تواند به تیم شما کمک کند تا بررسی ها را سرعت بخشد، بلکه به تیم طراحی و محصول شما اجازه می دهد تا به راحتی برخی از ویژگی های جدید را تأیید کند. آنها مجبور نیستند پروژه شما را بر روی رایانه خود اجرا کنند تا برخی تغییرات را پیش نمایش کنند: فرآیند بررسی باید تا حد امکان سریع و بدون درز باشد.
نسخه ها
آخرین چیزی که می خواهیم خودکار کنیم این است فرآیند انتشار. شما نمی خواهید مجبور باشید 20 اسکریپت را به صورت دستی و به ترتیب خاصی اجرا کنید تا برنامه خود را از شاخه اصلی خود به تولید برسانید. برای این من تمایل دارم آنچه را که a می نامم ترجیح دهم در حال انتشار یک شاخه در مخزن Github من و اسکریپت های خودکار اجرا شوند هر بار که شاخه اصلی در شاخه انتشار ادغام می شود. همچنین می توانید اسکریپت خودکار را در رویدادهای دیگر اجرا کنید، مانند زمانی که شما علامت گذاری انتشار یا شما حتی می توانید استقرار برنامه ریزی شده داشته باشید اگر سازمان شما آهنگ انتشار ثابتی دارد. در این مرحله بستگی به تیم یا سازمان شما دارد و اینکه چگونه/چه زمانی می خواهید انتشار خود را انجام دهید.
در اینجا یک نمونه از عملکرد GitHub است که یک اسکریپت (در این مورد، شما باید آن را با اسکریپت خود جایگزین کنید) پس از فشار دادن یک رویداد در شاخه انتشار، اجرا می کند:
نمونه گردش کار انتشار Github
1
name: Build and Deploy to Production14
- name: Checkout Commit15
uses: actions/checkout@v217
ref: ${{ github.event.pull_request.head.sha }}18
- name: Use Node.js ${{ matrix.node }}19
uses: actions/setup-node@v121
node: ${{ matrix.node }}22
- name: Install Dependencies24
yarn install --non-interactive29
- name: Deploy to production30
run: yarn deploy:production31
env: SOME_TOKEN_TO_DEPLOY=${{ secrets.MY_PRODUCTION_TOKEN }}
نکته مهم دیگر در مورد نسخه ها این است که وقتی آنها را خودکار کردید، باید تا آنجا که ممکن است آنها را منتشر کنید. با افزایش سرعت استقرار تولید، دامنه هر استقرار را محدود می کنید. این به نوبه خود تعداد مشکلاتی را که می تواند روی کاربر شما تأثیر بگذارد محدود می کند. علاوه بر این، میتوانید **پرچمهای ویژگی** را اضافه کنید تا امکان استقرار آهسته **یک ویژگی جدید بزرگ فراهم شود. این همچنین به شما کمک می کند تا هرگونه مشکل بالقوه ای را که ممکن است یک تغییر عظیم پس از عرضه به مرحله تولید ایجاد کند، کاهش دهید و همچنین کنترل بیشتری بر روی انتشار یک ویژگی جدید به شما می دهد. من به خصوص پرچم های ویژگی را دوست دارم زیرا آنها همچنین تجربه کاربر نهایی بهتری را ارائه می دهند، استقرار نرم تر است و می تواند هدفمندتر باشد: ممکن است بخواهید یک ویژگی را فقط برای زیرمجموعه ای از کاربران فعال کنید قبل از اینکه آن را به طور کلی در دسترس قرار دهید.
این مقاله شامل تمام مفاهیم، ابزارها و دانشی است که من روزانه برای ارسال نرم افزار بدون عرق کردن استفاده می کنم. من می دانم که بسیار متراکم است و چیزهای زیادی برای انجام دادن وجود دارد، اما واقعاً، اگر هر یک از این مراحل و مفاهیم را در پروژه خود پیاده کنید، می توانم به شما تضمین کنم که به شما، تیم و سازمانتان این امکان را می دهد که بهترین کاری که تا به حال انجام داده اید.
در زیر چند پیوند اضافی را مشاهده خواهید کرد که برای یادگیری در مورد تست و CI/CD مفید بوده اند. برخی از آنها پست های وبلاگ هستند، برخی از آنها کلاس هستند، من همه آنها را بسیار ارزشمند می دانم و مطمئن هستم که آنها به شما در سفر خود برای ایجاد یک محیط توسعه با سرعت بالا کمک می کنند و شما و تیمتان را غیرقابل توقف می کنند.
منابع:


