از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
استفاده از Spies برای تست در جاوا اسکریپت با تست نرم افزار Sinon.jsIn، یک «جاسوسی» روش استفاده از یک تابع را هنگام آزمایش ثبت می کند. این شامل چند بار فراخوانی شده، اینکه آیا با آرگومان های صحیح فراخوانی شده است یا خیر، و چه چیزی برگردانده شده است. در حالی که تست ها در درجه اول برای تایید خروجی یک تابع استفاده می شوند، گاهی اوقات …
سرفصلهای مطلب
معرفی
در تست نرم افزار، یک “جاسوس” روش استفاده از یک تابع را هنگام آزمایش ثبت می کند. این شامل چند بار فراخوانی شده، اینکه آیا با آرگومان های صحیح فراخوانی شده است یا خیر، و چه چیزی برگردانده شده است.
در حالی که تست ها در درجه اول برای اعتبار سنجی خروجی یک تابع استفاده می شوند، گاهی اوقات لازم است روش تعامل یک تابع با سایر بخش های کد را تأیید کنیم.
در این مقاله، نگاهی عمیقتر به اینکه جاسوسها چیست و چه زمانی باید استفاده شوند، خواهیم داشت. بعد جاسوسی میکنیم روی یک درخواست HTTP در حین استفاده Sinon.js در آزمون واحد جاوا اسکریپت
این مقاله دومین مقاله از مجموعه ای در مورد تکنیک های تست با Sinon.js است. توصیه می کنیم مقاله قبلی ما را نیز مطالعه کنید:
- استفاده از Stubs برای تست در جاوا اسکریپت با Sinon.js
- استفاده از Spies برای تست در جاوا اسکریپت با Sinon.js (تو اینجایی)
- استفاده از Mocks برای تست در جاوا اسکریپت با Sinon.js
جاسوس ها چیست؟
جاسوس یک شی در آزمایش است که تماس های برقرار شده به یک روش را ردیابی می کند. با ردیابی تماسهای آن، میتوانیم تأیید کنیم که از آن به روشی استفاده میشود که انتظار میرود تابع ما از آن استفاده کند.
درست به نام خود، یک جاسوس جزئیاتی در مورد روش استفاده از یک تابع به ما می دهد. چند بار صداش شد چه آرگومان هایی به تابع داده شد؟
بیایید تابعی را در نظر بگیریم که بررسی میکند کاربر وجود دارد یا خیر، و اگر وجود ندارد، یکی را در پایگاه داده ما ایجاد میکند. ما ممکن است پاسخ های پایگاه داده را خرد کنیم و داده های کاربر صحیح را در آزمایش خود دریافت کنیم. اما چگونه متوجه شویم که این تابع در مواردی که دادههای کاربر از قبل موجود را نداریم، در واقع یک کاربر ایجاد میکند؟ با یک جاسوس، مشاهده خواهیم کرد که چند بار تابع create-user فراخوانی می شود و مطمئن می شویم.
اکنون که می دانیم جاسوس چیست، بیایید در مورد موقعیت هایی که باید از آنها استفاده کنیم فکر کنیم.
چرا از جاسوس استفاده کنیم؟
جاسوسان در ارائه بینش نسبت به رفتار عملکردی که ما در حال آزمایش آن هستیم برتری دارند. در حالی که اعتبارسنجی ورودی ها و خروجی های یک تست بسیار مهم است، بررسی روش رفتار تابع می تواند در بسیاری از سناریوها حیاتی باشد:
وقتی عملکرد شما دارای عوارض جانبی است که در نتایج آن منعکس نمی شود، باید جاسوسی کنید روی روش هایی که استفاده می کند
یک مثال می تواند تابعی باشد که پس از برقراری تماس های زیاد با API های خارجی مختلف، JSON را به کاربر برمی گرداند. بار نهایی JSON به کاربر نمی گوید که تابع چگونه همه داده های خود را بازیابی می کند. جاسوسی که نظارت می کند چند بار از API های خارجی فراخوانی کرده و از چه ورودی هایی در آن تماس ها استفاده کرده است، به ما می گوید که چگونه.
بیایید ببینیم چگونه می توانیم از Sinon.js برای ایجاد جاسوس در کد خود استفاده کنیم.
استفاده از Sinon.Js برای ایجاد جاسوس
راه های مختلفی برای ایجاد جاسوس با Sinon.js وجود دارد که هر کدام مزایا و معایب خود را دارند. این آموزش متمرکز خواهد بود روی دو روش زیر که جاسوسان را هدف قرار می دهد روی یک تابع در یک زمان:
- یک تابع ناشناس که آرگومان ها، مقادیر و فراخوانی های انجام شده به یک متد را ردیابی می کند.
- یک بسته بندی برای یک تابع موجود.
ابتدا اجازه دهید پروژه خود را راه اندازی کنیم تا بتوانیم فایل های آزمایشی خود را اجرا کرده و از Sinon.js استفاده کنیم.
برپایی
بیایید با ایجاد یک پوشه برای ذخیره کد جاوا اسکریپت شروع کنیم. یک پوشه جدید ایجاد کنید و به آن بروید:
$ mkdir SpyTests
$ cd SpyTests
NPM را راهاندازی کنید تا بتوانید بستههایی را که نصب میکنید پیگیری کنید:
$ npm init -y
حالا بیایید وابستگی های آزمایشی خود را نصب کنیم. نصب می کنیم موکا و چای برای اجرای آزمایشات ما به همراه Sinon.js:
$ npm i mocha chai sinon --save-dev
راه اندازی ما کامل شد! بیایید با استفاده از جاسوسان به عنوان توابع ناشناس شروع کنیم.
جاسوسان با عملکردهای ناشناس
بهعنوان توابع ناشناس، جاسوسهای Sinon.js اغلب در مواردی مفید هستند که میخواهیم توابع درجه بالاتری را آزمایش کنیم که توابع دیگر، یعنی callbacks را به عنوان آرگومان میگیرند. بیایید به یک مثال اساسی نگاه کنیم که دوباره آن را پیاده سازی می کند Array.prototype.map()
با پاسخ به تماس:
ایجاد دو فایل به عنوان مثال mapOperations.js
و mapOperations.test.js
درون spyTests
دایرکتوری به شرح زیر
$ touch mapOperations.js mapOperations.test.js
کد زیر را در قسمت وارد کنید mapOperations.js
فایل:
const map = (array, operation) => {
let arrayOfMappedItems = ();
for (let item of array) {
arrayOfMappedItems.push(operation(item));
}
return arrayOfMappedItems;
};
console.log(map(({ name: 'john', role: 'author'}, { name: 'jane', role: 'owner'}), user => user.name));
module.exports = { map };
در کد بالا، map()
یک آرایه را به عنوان اولین آرگومان و تابع فراخوانی می گیرد، operation()
، که آیتم های آرایه را به عنوان آرگومان دوم خود تبدیل می کند.
درون map()
تابع، از طریق آرایه تکرار می کنیم و عملیات را اعمال می کنیم روی هر آیتم آرایه، سپس نتیجه را فشار دهید arrayOfMappedItems
آرایه.
وقتی این مثال را اجرا می کنید روی را console، باید نتیجه زیر را دریافت کنید:
$ node mapOperations.js
( 'john', 'jane' )
برای آزمایش اینکه آیا operation()
تابع توسط ما فراخوانی شد map()
ما می توانیم یک جاسوس ناشناس ایجاد کرده و به آن منتقل کنیم map()
عملکرد به شرح زیر است:
const { map } = require('./mapOperations');
const sinon = require('sinon');
const expect = require('chai').expect;
describe('test map', () => {
const operation = sinon.spy();
it('calls operation', () => {
map(({ name: 'foo', role: 'author'}, { name: 'bar', role: 'owner'}), operation);
expect(operation.called);
});
});
در حالی که تماس ما واقعاً آرایه را تغییر نمی دهد، جاسوس ما می تواند تأیید کند که عملکردی که ما آزمایش می کنیم واقعاً از آن استفاده می کند. این زمانی تایید می شود expect(operation.called);
در آزمون مردود نمی شود
بیایید ببینیم آیا آزمون ما قبول می شود یا خیر! تست را اجرا کنید، باید خروجی زیر را دریافت کنید:
$ mocha mapOperations.test.js
test map
✓ calls operation
1 passing (4ms)
✨ Done in 0.58s.
کار می کند! اکنون مطمئن هستیم که تابع ما از هر callbackی که در آرگومان هایش قرار می دهیم استفاده خواهد کرد. بیایید ببینیم چگونه می توانیم یک تابع یا روش را با استفاده از یک جاسوس بسته بندی کنیم.
جاسوسها بهعنوان بستهبندی عملکرد یا روش
در مقاله قبلی، دیدیم که چگونه میتوانیم درخواست HTTP را در تستهای واحد خود خرد کنیم. ما از همان کد استفاده می کنیم تا نشان دهیم چگونه می توانیم از Sinon.js برای جاسوسی استفاده کنیم روی یک درخواست HTTP
در یک فایل جدید به نام index.js
، کد زیر را اضافه کنید:
const request = require('request');
module.exports = {
getAlbumById: async function(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));
});
});
}
};
برای جمع بندی، getAlbumById()
متد یک JSON API را فراخوانی می کند که لیستی از عکس ها را از آلبومی که شناسه آن را به عنوان پارامتر ارسال می کنیم، واکشی می کند. قبلا، ما را خمیده request.get()
روشی برای بازگرداندن یک لیست ثابت از عکس ها.
این بار جاسوسی خواهیم کرد روی را request.get()
بنابراین ما می توانیم تأیید کنیم که تابع ما یک درخواست HTTP به API می کند. ما همچنین بررسی میکنیم که یک بار درخواست را ارسال کرده باشد، که خوب است زیرا نمیخواهیم باگی که نقطه پایانی API را هرزنامه کند.
در یک فایل تست جدید به نام index.test.js
کد جاوا اسکریپت زیر را خط به خط بنویسید:
const expect = require('chai').expect;
const request = require('request');
const sinon = require('sinon');
const index = require('./index');
describe('test getPhotosByAlbumId', () => {
let requestSpy;
before(() => {
requestSpy = sinon.spy(request, 'get');
});
after(() => {
request.get.restore();
});
it('should getPhotosByAlbumId', (done) => {
index.getAlbumById(2).then((photos) => {
expect(requestSpy.calledOnce);
expect(requestSpy.args(0)(0)).to.equal("https://jsonplaceholder.typicode.com/albums/2/photos؟_limit=3");
photos.forEach(photo => {
expect(photo).to.have.property('id');
expect(photo).to.have.property('title');
expect(photo).to.have.property('url');
});
done();
});
});
});
در تست بالا، ما را پیچیده کردیم request.get()
روش با جاسوس در حین نصب در before()
تابع. هنگامی که تست را در قسمت حذف می کنیم، عملکرد را بازیابی می کنیم after()
تابع.
در مورد آزمایشی، ما این ادعا را داشتیم که requestSpy
، شیئی که ردیابی می کند request.get()
استفاده، فقط یک تماس را ضبط می کند. سپس عمیقتر میشویم تا تأیید کنیم که اولین استدلال آن در مورد آن است request.get()
تماس، نشانی اینترنتی JSON API است. سپس برای اطمینان از اینکه عکسهای بازگردانده شده دارای ویژگیهای مورد انتظار هستند، اظهاراتی کردیم.
هنگام اجرای تست، باید خروجی زیر را دریافت کنید:
$ mocha index.test.js
test getPhotosByAlbumId
✓ should getPhotosByAlbumId (570ms)
1 passing (587ms)
✨ Done in 2.53s.
لطفاً توجه داشته باشید که این آزمایش یک درخواست شبکه واقعی به API ارائه کرد. جاسوس می پیچد دور و بر عملکرد، آن را انجام می دهد نه عملکرد آن را جایگزین کنید!
همچنین، مقالات خرد Sinon.js در حال حاضر جاسوس هستند! اگر یک نمونه خرد آزمایشی ایجاد کنید، میتوانید ببینید که چند بار فراخوانی شده و آرگومانهایی که به تابع ارسال شدهاند.
نتیجه
یک جاسوس در آزمایش راهی برای ردیابی تماسهای برقرار شده با یک روش به ما میدهد تا بتوانیم بررسی کنیم که مطابق انتظار کار میکند. ما از spies برای بررسی اینکه آیا یک متد فراخوانی شده است یا نه، چند بار فراخوانی شده است، با چه آرگومان هایی فراخوانی شده است و همچنین مقداری که هنگام فراخوانی برگردانده شده است، استفاده می کنیم.
در این مقاله مفهوم جاسوس را معرفی کردیم و دیدیم که چگونه می توانیم از Sinon.js برای ایجاد جاسوس استفاده کنیم. ما همچنین بررسی کردیم که چگونه میتوانیم جاسوسها را بهعنوان عملکردهای ناشناس ایجاد کنیم و چگونه میتوانیم از آنها برای بستهبندی روشها استفاده کنیم. برای موارد استفاده پیشرفته تر، Sinon.js یک API جاسوسی غنی ارائه می دهد که می توانیم از آن استفاده کنیم. برای جزئیات بیشتر، می توان به اسناد دسترسی داشت اینجا.
منتشر شده در 1403-01-22 01:42:03