از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
استفاده از Stubs برای تست در جاوا اسکریپت با Sinon.jsTesting بخش اساسی توسعه نرم افزار است. process. هنگام ایجاد برنامه های کاربردی وب، ما با API های شخص ثالث، پایگاه های داده یا سایر خدمات موجود در محیط خود تماس می گیریم. بنابراین، آزمایشهای ما باید تأیید کند که این درخواستها ارسال شده و پاسخها به درستی بررسی میشوند. با این حال، ممکن است همیشه نتوانیم با …
سرفصلهای مطلب
معرفی
تست بخش اساسی توسعه نرم افزار است process. هنگام ایجاد برنامه های کاربردی وب، ما با API های شخص ثالث، پایگاه های داده یا سایر خدمات موجود در محیط خود تماس می گیریم. بنابراین، آزمایشهای ما باید تأیید کند که این درخواستها ارسال شده و پاسخها به درستی بررسی میشوند. با این حال، ممکن است همیشه نتوانیم با آن سرویسهای خارجی در هنگام اجرای آزمایشها ارتباط برقرار کنیم.
در رایانه توسعه محلی خود، ممکن است کلیدهای API شرکت یا اعتبار پایگاه داده برای اجرای موفقیت آمیز آزمایش نداشته باشیم. به همین دلیل است که ما گاهی اوقات پاسخ های HTTP یا پایگاه داده را با a “جعل” می کنیم خرد، فریب کد ما به گونه ای که مانند یک درخواست واقعی رفتار کند، انجام شد.
در این مقاله، ما با نگاهی به این که خرد چیست و چرا میخواهیم از آنها استفاده کنیم، شروع میکنیم. سپس ما اهرم خواهیم کرد Sinon.js، یک کتابخانه آزمایشی محبوب جاوا اسکریپت، برای ایجاد تست های واحد برای جاوا اسکریپت که درخواست HTTP را متوقف می کند.
بعد پیگیری میکنیم روی این با مقالات روی جاسوس ها و تمسخرها:
- استفاده از Stubs برای تست در جاوا اسکریپت با Sinon.js (تو اینجایی)
- استفاده از Spies برای تست در جاوا اسکریپت با Sinon.js
- استفاده از Mocks برای تست در جاوا اسکریپت با Sinon.js
Stubs چیست؟
یک تست خرد تابع یا شی ای است که رفتار واقعی یک ماژول را با یک پاسخ ثابت جایگزین می کند. خرد فقط میتواند پاسخ ثابتی را که برای بازگرداندن آن برنامهریزی شده بود، برگرداند.
یک خرد را می توان به عنوان یک فرض برای آزمایش ما در نظر گرفت – اگر فرض کنیم که یک سرویس خارجی این پاسخ را برمی گرداند، عملکرد تابع اینگونه است.
تصور کنید که تابعی دارید که درخواست HTTP را می پذیرد و داده ها را از نقطه پایانی GraphQL دریافت می کند. اگر در آزمایشهای خود نتوانیم به نقطه پایانی GraphQL متصل شویم، پاسخ آن را خرد میکنیم تا کد ما طوری اجرا شود که گویی GraphQL واقعاً ضربه خورده است. کد تابع ما تفاوت بین پاسخ واقعی GraphQL در مقابل پاسخ stubbed ما را نمی داند.
بیایید به سناریوهایی نگاه کنیم که در آن تخطی مفید است.
چرا از Stubs استفاده کنیم؟
هنگام درخواست برای سرویس های خارجی در یک آزمایش، می توانید با این مشکلات مواجه شوید:
- عدم موفقیت در تست ها به دلیل خطاهای اتصال به شبکه به جای خطاهای کد
- زمان های طولانی به عنوان تاخیر شبکه به زمان تست می افزاید
- در صورت بروز خطای پیکربندی، به اشتباه دادههای تولید را با آزمایشها تحت تأثیر قرار میدهد
ما میتوانیم با جدا کردن آزمایشهایمان و قطع کردن این تماسهای سرویس خارجی، این مشکلات را برطرف کنیم. هیچ وابستگی به شبکه وجود نخواهد داشت، که باعث می شود آزمایش های ما قابل پیش بینی تر باشد و احتمال شکست آنها کمتر شود. بدون تأخیر شبکه، انتظار میرود که تستهای ما نیز سریعتر باشند.
سناریوهایی وجود دارد که در آن درخواست های خارجی کار نمی کنند. به عنوان مثال، در فرآیندهای ساخت CI/CD، مسدود کردن درخواستهای خارجی هنگام اجرای آزمایشها به دلایل امنیتی رایج است. همچنین این احتمال وجود دارد که زمانی ما کدی بنویسیم که بستگی دارد روی سرویسی که هنوز در حال توسعه است و در حالتی نیست که بتوان از آن استفاده کرد.
در این موارد، خردهها بسیار مفید هستند، زیرا به ما اجازه میدهند کد خود را حتی زمانی که سرویس در دسترس نیست، آزمایش کنیم.
اکنون که می دانیم خرد چیست و چرا مفید هستند، بیایید از Sinon.js استفاده کنیم تا تجربیات عملی در مورد خرده بگیریم.
استفاده از Sinon.js برای ایجاد یک Stub
ما از Sinon.js برای ارسال پاسخ از یک JSON API که لیستی از عکسهای یک آلبوم را بازیابی میکند، استفاده میکنیم. تست های ما با ایجاد خواهد شد موکا و چای کتابخانه های آزمایشی اگر می خواهید قبل از ادامه در مورد آزمایش با موکا و چای بیشتر بدانید، می توانید راهنمای ما را دنبال کنید.
برپایی
اول، در شما terminal یک پوشه جدید ایجاد کنید و به آن بروید:
$ mkdir PhotoAlbum
$ cd PhotoAlbum
NPM را راهاندازی کنید تا بتوانید بستههایی را که نصب میکنید پیگیری کنید:
$ npm init -y
پس از تکمیل، میتوانیم شروع به نصب وابستگیهای خود کنیم. ابتدا، بیایید کتابخانه درخواست را نصب کنیم، که توسط کد ما برای ایجاد یک درخواست HTTP به API استفاده می شود. در شما terminal، وارد:
$ npm i request --save
اکنون، بیایید تمام کتابخانه های آزمایشی را به عنوان وابستگی های توسعه دهنده نصب کنیم. کد تست در تولید استفاده نمیشود، بنابراین کتابخانههای آزمایشی را بهعنوان یک کد معمولی وابسته به کد نصب نمیکنیم --save
گزینه. در عوض، ما از --save-dev
گزینه ای برای گفتن به NPM که این وابستگی ها فقط باید در محیط توسعه/تست ما استفاده شوند. دستور را در خود وارد کنید terminal:
$ npm i mocha chai sinon --save-dev
با وارد کردن همه کتابخانههایمان، یک کتابخانه جدید ایجاد میکنیم index.js
فایل و کد را اضافه کنید تا درخواست API را در آنجا انجام دهید. می توانید استفاده کنید terminal برای ایجاد index.js
فایل:
$ touch index.js
در ویرایشگر متن یا IDE خود، کد زیر را بنویسید:
const request = require('request');
const getPhotosByAlbumId = (id) => {
const requestUrl = `https://jsonplaceholder.typicode.com/albums/${id}/photos؟_limit=3`;
return new Promise((resolve, reject) => {
request.get(requestUrl, (err, res, body) => {
if (err) {
return reject(err);
}
resolve(JSON.parse(body));
});
});
};
module.exports = getPhotosByAlbumId;
این تابع یک API را فراخوانی می کند که لیستی از عکس ها را از آلبومی که شناسه آن به عنوان پارامتر به تابع ارسال شده است، برمی گرداند. ما پاسخ را فقط به بازگرداندن سه عکس محدود می کنیم.
اکنون تست هایی را برای عملکرد خود می نویسیم تا تأیید کنیم که مطابق انتظار کار می کند. اولین آزمایش ما از خرد استفاده نمی کند، اما در عوض درخواست واقعی را انجام می دهد.
تست بدون خرد
ابتدا بیایید یک فایل بسازیم تا تست های خود را در آن بنویسیم terminal یا در غیر این صورت، یک index.test.js
فایل در دایرکتوری فعلی:
$ touch index.test.js
کد ما آزمایش میکند که سه عکس را پس میگیریم، و هر عکس مورد انتظار را دارد id
، title
، و url
خواص
در index.test.js
فایل، کد زیر را اضافه کنید:
const expect = require('chai').expect;
const getPhotosByAlbumId = require('./index');
describe('withoutStub: getPhotosByAlbumId', () => {
it('should getPhotosByAlbumId', (done) => {
getPhotosByAlbumId(1).then((photos) => {
expect(photos.length).to.equal(3);
photos.forEach(photo => {
expect(photo).to.have.property('id');
expect(photo).to.have.property('title');
expect(photo).to.have.property('url');
});
done();
});
});
});
در این آزمون ابتدا نیاز داریم expect()
تابع Chai، و سپس نیاز به getPhotosByAlbumId()
عملکرد از ما index.js
فایل.
ما از موکا استفاده می کنیم describe()
و it()
توابع تا بتوانیم از آن استفاده کنیم mocha
دستور اجرای کد به صورت آزمایشی
قبل از اجرای تست خود، باید یک اسکریپت به package.json خود اضافه کنیم تا تست های خود را اجرا کنیم. در package.json
فایل، موارد زیر را اضافه کنید:
"scripts": {
"test": "mocha index.test.js"
}
اکنون تست خود را با دستور زیر اجرا کنید:
$ npm test
شما باید این خروجی را ببینید:
$ mocha index.test.js
withoutStub: getPhotosByAlbumId
✓ should getPhotosByAlbumId (311ms)
1 passing (326ms)
در این مورد، آزمایش 326 میلیثانیه طول کشید، اما بسته به آن ممکن است متفاوت باشد روی سرعت اینترنت و موقعیت مکانی شما
اگر اتصال اینترنتی فعال نداشته باشید، این آزمایش نمیگذرد زیرا درخواست HTTP با شکست مواجه میشود. اگرچه این بدان معنا نیست که عملکرد مطابق انتظار عمل نمی کند. بیایید از یک خرد استفاده کنیم تا بتوانیم رفتار عملکرد خود را بدون وابستگی به شبکه آزمایش کنیم.
تست با Stubs
بیایید تابع خود را بازنویسی کنیم تا درخواست را در API قرار دهیم و یک لیست از پیش تعریف شده از عکس ها را برگردانیم:
const expect = require('chai').expect;
const request = require('request');
const sinon = require('sinon');
const getPhotosByAlbumId = require('./index');
describe('with Stub: getPhotosByAlbumId', () => {
before(() => {
sinon.stub(request, 'get')
.yields(null, null, JSON.stringify((
{
"albumId": 1,
"id": 1,
"title": "accusamus beatae ad facilis cum similique qui sunt",
"url": "https://via.placeholder.com/600/92c952",
"thumbnailUrl": "https://via.placeholder.com/150/92c952"
},
{
"albumId": 1,
"id": 2,
"title": "reprehenderit est deserunt velit ipsam",
"url": "https://via.placeholder.com/600/771796",
"thumbnailUrl": "https://via.placeholder.com/150/771796"
},
{
"albumId": 1,
"id": 3,
"title": "officia porro iure quia iusto qui ipsa ut modi",
"url": "https://via.placeholder.com/600/24f355",
"thumbnailUrl": "https://via.placeholder.com/150/24f355"
}
)));
});
after(() => {
request.get.restore();
});
it('should getPhotosByAlbumId', (done) => {
getPhotosByAlbumId(1).then((photos) => {
expect(photos.length).to.equal(3);
photos.forEach(photo => {
expect(photo).to.have.property('id');
expect(photo).to.have.property('title');
expect(photo).to.have.property('url');
});
done();
});
});
});
قبل از اجرای آزمایش، به Sinon.js میگوییم که آن را خرد کند get()
عملکرد از request
شیئی که در getPhotosByAlbumId ()
.
استدلال ها به yields()
تابع stub آرگومان هایی هستند که به callback درخواست دریافت ارسال می شوند. عبور می کنیم null
برای err
و res
پارامترها و آرایه ای از داده های آلبوم عکس جعلی برای body
پارامتر.
توجه داشته باشید:
after()
تابع پس از اتمام تست اجرا می شود. در این مورد ما رفتار را بازیابی می کنیمrequest
کتابخانهget()
تابع. بهترین شیوه ها، ایالت های آزمون ما را تشویق می کند تا برای هر آزمون مستقل باشند. با بازیابی تابع، تغییراتی که ما برای این تست انجام دادیم بر روش استفاده از آن در تستهای دیگر تأثیری نخواهد داشت.
مانند قبل، این تست را با آن اجرا می کنیم npm test
. شما باید خروجی زیر را ببینید:
$ mocha index.test.js
with Stub: getPhotosByAlbumId
✓ should getPhotosByAlbumId
1 passing (37ms)
عالی! اکنون بدون اتصال به اینترنت، هنوز مطمئن هستیم که عملکرد ما با داده های مورد انتظار به خوبی کار می کند. تست هم سریعتر اجرا شد! بدون درخواست شبکه، ما به سادگی باید داده ها را از حافظه دریافت کنیم.
نتیجه
یک خرد جایگزین تابعی است که هنگام فراخوانی داده های ثابت را برمی گرداند. ما معمولاً درخواستها را به سیستمهای خارجی ارسال میکنیم تا اجرای آزمایشی را قابل پیشبینیتر کنیم و نیاز به اتصالات شبکه را از بین ببریم.
Sinon.js را می توان در کنار سایر چارچوب های آزمایشی برای توابع خرد استفاده کرد. در این مقاله، ما یک درخواست HTTP GET را جمع آوری کردیم تا آزمایش ما بدون اتصال به اینترنت اجرا شود. همچنین زمان آزمون را نیز کاهش داد.
اگر می خواهید کد این آموزش را ببینید، می توانید آن را پیدا کنید اینجا.
در مقاله بعدی ما ادامه می دهیم روی با Sinon.js و روش استفاده از جاسوس ها برای آزمایش جاوا اسکریپت را پوشش دهید.
(برچسبها برای ترجمه)# جاوا اسکریپت
منتشر شده در 1403-01-22 08:02:03