این صفحه بهترین روشها و ابزارها را برای نوشتن تستهای واحد برای عملکردهای شما، مانند تستهایی که بخشی از سیستم یکپارچهسازی مداوم (CI) هستند، شرح میدهد. برای آسانتر کردن آزمایش، Firebase Firebase Test SDK برای Cloud Functions ارائه میکند. در npm به عنوان firebase-functions-test
توزیع میشود و یک SDK آزمایشی همراه با firebase-functions
است. Firebase Test SDK برای Cloud Functions :
- از راهاندازی و حذف مناسب برای تستهای شما مراقبت میکند، مانند تنظیم و غیرفعال کردن متغیرهای محیطی مورد نیاز
firebase-functions
. - داده های نمونه و زمینه رویداد را ایجاد می کند، به طوری که شما فقط باید فیلدهایی را که مربوط به آزمون شما هستند مشخص کنید.
تنظیم تست
با اجرای دستورات زیر در پوشه توابع خود، هم firebase-functions-test
و هم Mocha ، یک چارچوب آزمایشی را نصب کنید:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
سپس یک پوشه test
در داخل پوشه توابع ایجاد کنید، یک فایل جدید در داخل آن برای کد تست خود ایجاد کنید و نام آن را چیزی مانند index.test.js
بگذارید.
در نهایت، functions/package.json
را تغییر دهید تا موارد زیر را اضافه کنید:
"scripts": {
"test": "mocha --reporter spec"
}
هنگامی که تست ها را نوشتید، می توانید با اجرای npm test
در دایرکتوری توابع خود، آنها را اجرا کنید.
راه اندازی Firebase Test SDK برای Cloud Functions
دو راه برای استفاده از firebase-functions-test
وجود دارد:
- حالت آنلاین (توصیه میشود): تستهایی را بنویسید که با پروژه Firebase که به آزمایش اختصاص داده شده است، تعامل داشته باشند تا در واقع نوشتن پایگاه داده، ایجاد کاربر و غیره اتفاق بیفتد و کد تست شما بتواند نتایج را بررسی کند. این همچنین به این معنی است که سایر SDK های Google مورد استفاده در توابع شما نیز کار خواهند کرد.
- حالت آفلاین: تست های واحد siled و آفلاین را بدون عوارض جانبی بنویسید. این بدان معناست که هر فراخوانی متدی که با یک محصول Firebase تعامل دارد (مثلاً نوشتن در پایگاه داده یا ایجاد یک کاربر) باید stubbed شود. اگر دارای عملکردهای Cloud Firestore یا Realtime Database هستید، معمولاً استفاده از حالت آفلاین توصیه نمی شود، زیرا پیچیدگی کد آزمایشی شما را بسیار افزایش می دهد.
راه اندازی SDK در حالت آنلاین (توصیه می شود)
اگر میخواهید آزمایشهایی بنویسید که با یک پروژه آزمایشی تعامل دارند، باید مقادیر پیکربندی پروژه را که برای مقداردهی اولیه برنامه از طریق firebase-admin
مورد نیاز است و مسیر فایل کلید حساب سرویس را ارائه کنید.
برای دریافت مقادیر پیکربندی پروژه Firebase:
- تنظیمات پروژه خود را در کنسول Firebase باز کنید.
- در برنامه های شما، برنامه مورد نظر را انتخاب کنید.
در قسمت سمت راست، گزینه دانلود فایل پیکربندی برنامه های اپل و اندروید را انتخاب کنید.
برای برنامه های وب، Config را برای نمایش مقادیر پیکربندی انتخاب کنید.
برای ایجاد یک فایل کلیدی:
- صفحه حسابهای سرویس کنسول Google Cloud را باز کنید.
- حساب سرویس پیشفرض App Engine را انتخاب کنید و از منوی گزینهها در سمت راست برای انتخاب کلید ایجاد استفاده کنید.
- وقتی از شما خواسته شد، JSON را برای نوع کلید انتخاب کنید و روی ایجاد کلیک کنید.
پس از ذخیره فایل کلید، SDK را مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')({
databaseURL: 'https://my-project.firebaseio.com',
storageBucket: 'my-project.appspot.com',
projectId: 'my-project',
}, 'path/to/serviceAccountKey.json');
SDK را در حالت آفلاین راه اندازی کنید
اگر می خواهید تست های کاملا آفلاین بنویسید، می توانید SDK را بدون هیچ پارامتری مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
مسخره کردن مقادیر پیکربندی
اگر functions.config()
در کد توابع خود استفاده می کنید، می توانید مقادیر پیکربندی را مسخره کنید. برای مثال، اگر functions/index.js
حاوی کد زیر باشد:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
سپس میتوانید مقدار داخل فایل آزمایشی خود را به شکل زیر مسخره کنید:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
وارد کردن توابع شما
برای وارد کردن توابع خود، از require
برای وارد کردن فایل توابع اصلی خود به عنوان یک ماژول استفاده کنید. مطمئن شوید که این کار را فقط پس از مقداردهی اولیه firebase-functions-test
و مسخره کردن مقادیر پیکربندی انجام دهید.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
اگر firebase-functions-test
در حالت آفلاین مقداردهی اولیه کردید و در کد توابع خود admin.initializeApp()
دارید، باید قبل از وارد کردن توابع، آن را خرد کنید:
// If index.js calls admin.initializeApp at the top of the file, // we need to stub it out before requiring index.js. This is because the // functions will be executed as a part of the require process. // Here we stub admin.initializeApp to be a dummy function that doesn't do anything. adminInitStub = sinon.stub(admin, 'initializeApp'); // Now we can require index.js and save the exports inside a namespace called myFunctions. myFunctions = require('../index');
تست توابع پس زمینه (غیر HTTP).
فرآیند آزمایش توابع غیر HTTP شامل مراحل زیر است:
- تابعی را که می خواهید آزمایش کنید با روش
test.wrap
بپیچید - داده های آزمایشی را بسازید
- تابع پیچیده شده را با داده های آزمایشی که ساخته اید و هر فیلد زمینه رویدادی که می خواهید مشخص کنید فراخوانی کنید.
- در مورد رفتار اظهار نظر کنید.
ابتدا تابعی را که می خواهید آزمایش کنید بپیچید. فرض کنید یک تابع در functions/index.js
به نام makeUppercase
دارید که میخواهید آن را آزمایش کنید. موارد زیر را در functions/test/index.test.js
بنویسید
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
تابعی است که هنگام فراخوانی makeUppercase
فراخوانی می کند. wrapped
2 پارامتر می گیرد:
- داده (الزامی): داده هایی برای ارسال به
makeUppercase
. این به طور مستقیم با اولین پارامتر ارسال شده به تابعی که نوشتید مطابقت دارد.firebase-functions-test
روش هایی را برای ساخت داده های سفارشی یا داده های نمونه ارائه می دهد. - eventContextOptions (اختیاری): فیلدهایی از زمینه رویداد که می خواهید مشخص کنید. زمینه رویداد دومین پارامتری است که به کنترل کننده تابعی که نوشته اید ارسال می شود. اگر هنگام فراخوانی
wrapped
پارامترeventContextOptions
را وارد نکنید، یک زمینه رویداد همچنان با فیلدهای معقول ایجاد می شود. شما می توانید برخی از فیلدهای تولید شده را با مشخص کردن آنها در اینجا لغو کنید. توجه داشته باشید که فقط باید فیلدهایی را که میخواهید لغو شوند، وارد کنید. هر فیلدی که شما لغو نکرده اید ایجاد می شود.
const data = … // See next section for constructing test data
// Invoke the wrapped function without specifying the event context.
wrapped(data);
// Invoke the function, and specify params
wrapped(data, {
params: {
pushId: '234234'
}
});
// Invoke the function, and specify auth and auth Type (for real time database functions only)
wrapped(data, {
auth: {
uid: 'jckS2Q0'
},
authType: 'USER'
});
// Invoke the function, and specify all the fields that can be specified
wrapped(data, {
eventId: 'abc',
timestamp: '2018-03-23T17:27:17.099Z',
params: {
pushId: '234234'
},
auth: {
uid: 'jckS2Q0' // only for real time database functions
},
authType: 'USER' // only for real time database functions
});
ساخت داده های آزمایشی
اولین پارامتر یک تابع پیچیده، داده های آزمایشی است که تابع زیرین را با آن فراخوانی می کند. روش های مختلفی برای ساخت داده های آزمایشی وجود دارد.
استفاده از داده های سفارشی
firebase-functions-test
تعدادی توابع برای ساخت داده های مورد نیاز برای آزمایش توابع شما دارد. برای مثال، از test.firestore.makeDocumentSnapshot
برای ایجاد یک Firestore DocumentSnapshot
استفاده کنید. آرگومان اول داده است و آرگومان دوم مسیر مرجع کامل است و یک آرگومان سوم اختیاری برای سایر ویژگی های عکس فوری وجود دارد که می توانید مشخص کنید.
// Make snapshot
const snap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Call wrapped function with the snapshot
const wrapped = test.wrap(myFunctions.myFirestoreDeleteFunction);
wrapped(snap);
اگر در حال آزمایش یک تابع onUpdate
یا onWrite
هستید، باید دو عکس فوری ایجاد کنید: یکی برای حالت قبل و دیگری برای حالت بعد. سپس، می توانید از متد makeChange
برای ایجاد یک شی Change
با این عکس های فوری استفاده کنید.
// Make snapshot for state of database beforehand
const beforeSnap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Make snapshot for state of database after the change
const afterSnap = test.firestore.makeDocumentSnapshot({foo: 'faz'}, 'document/path');
const change = test.makeChange(beforeSnap, afterSnap);
// Call wrapped function with the Change object
const wrapped = test.wrap(myFunctions.myFirestoreUpdateFunction);
wrapped(change);
به مرجع API برای توابع مشابه برای همه انواع داده های دیگر مراجعه کنید.
با استفاده از داده های نمونه
اگر نیازی به سفارشی سازی داده های مورد استفاده در تست های خود ندارید، firebase-functions-test
روش هایی را برای تولید داده های نمونه برای هر نوع تابع ارائه می دهد.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
مرجع API را برای روشهایی برای دریافت نمونه دادهها برای هر نوع تابع ببینید.
استفاده از داده های خرد شده (برای حالت آفلاین)
اگر SDK را در حالت آفلاین مقداردهی اولیه کرده اید و در حال آزمایش عملکرد Cloud Firestore یا Realtime Database هستید، باید به جای ایجاد یک DocumentSnapshot
یا DataSnapshot
واقعی از یک شی ساده با خرد استفاده کنید.
فرض کنید در حال نوشتن یک آزمون واحد برای تابع زیر هستید:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
در داخل تابع، snap
دو بار استفاده می شود:
-
snap.val()
-
snap.ref.parent.child('uppercase').set(uppercase)
در کد تست، یک شیء ساده ایجاد کنید که در آن هر دو مسیر کد کار کنند و از Sinon برای Stub متدها استفاده کنید.
// The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true);
اظهار نظر
پس از مقداردهی اولیه SDK، بسته بندی توابع، و ساخت داده ها، می توانید توابع پیچیده شده را با داده های ساخته شده فراخوانی کنید و در مورد رفتار اظهار نظر کنید. برای بیان این ادعاها می توانید از کتابخانه ای مانند چای استفاده کنید.
اظهار نظر در حالت آنلاین
اگر Firebase Test SDK برای Cloud Functions در حالت آنلاین راهاندازی کرده باشید، میتوانید با استفاده از firebase-admin
SDK ادعا کنید که اقدامات مورد نظر (مانند نوشتن پایگاه داده) انجام شده است.
مثال زیر بیان می کند که "INPUT" در پایگاه داده پروژه آزمایشی نوشته شده است.
// Create a DataSnapshot with the value 'input' and the reference path 'messages/11111/original'. const snap = test.database.makeDataSnapshot('input', 'messages/11111/original'); // Wrap the makeUppercase function const wrapped = test.wrap(myFunctions.makeUppercase); // Call the wrapped function with the snapshot you constructed. return wrapped(snap).then(() => { // Read the value of the data at messages/11111/uppercase. Because `admin.initializeApp()` is // called in functions/index.js, there's already a Firebase app initialized. Otherwise, add // `admin.initializeApp()` before this line. return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => { // Assert that the value is the uppercased version of our input. assert.equal(createdSnap.val(), 'INPUT'); }); });
اظهار نظر در حالت آفلاین
می توانید در مورد مقدار بازگشتی مورد انتظار تابع اظهار نظر کنید:
const childParam = 'uppercase'; const setParam = 'INPUT'; // Stubs are objects that fake and/or record function calls. // These are excellent for verifying that functions have been called and to validate the // parameters passed to those functions. const childStub = sinon.stub(); const setStub = sinon.stub(); // The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true); // Wrap the makeUppercase function. const wrapped = test.wrap(myFunctions.makeUppercase); // Since we've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was // called with the parameters we expect, we assert that it indeed returned true. return assert.equal(wrapped(snap), true);
همچنین میتوانید از جاسوسهای Sinon برای تأیید اینکه متدهای خاصی فراخوانی شدهاند و با پارامترهایی که انتظار دارید استفاده کنید.
تست توابع HTTP
برای آزمایش توابع HTTP onCall، از همان رویکرد آزمایش توابع پسزمینه استفاده کنید.
اگر در حال آزمایش توابع HTTP onRequest هستید، باید از firebase-functions-test
استفاده کنید اگر:
- شما از
functions.config()
استفاده می کنید - عملکرد شما با یک پروژه Firebase یا سایر APIهای Google تعامل دارد و میخواهید از یک پروژه Firebase واقعی و اعتبار آن برای آزمایشهای خود استفاده کنید.
یک تابع onRequest HTTP دو پارامتر دارد: یک شی درخواست و یک شی پاسخ. در اینجا نحوه آزمایش تابع مثال addMessage()
آمده است:
- تابع تغییر مسیر را در شیء پاسخ لغو کنید، زیرا
sendMessage()
آن را فراخوانی می کند. - در تابع تغییر مسیر، از chai.assert برای کمک به اظهارنظر در مورد پارامترهایی که تابع تغییر مسیر باید با چه پارامترهایی فراخوانی شود، استفاده کنید:
// A fake request object, with req.query.text set to 'input' const req = { query: {text: 'input'} }; // A fake response object, with a stubbed redirect function which asserts that it is called // with parameters 303, 'new_ref'. const res = { redirect: (code, url) => { assert.equal(code, 303); assert.equal(url, 'new_ref'); done(); } }; // Invoke addMessage with our fake request and response objects. This will cause the // assertions in the response object to be evaluated. myFunctions.addMessage(req, res);
پاکسازی آزمایشی
در انتهای کد آزمایشی خود، تابع پاکسازی را فراخوانی کنید. این کار متغیرهای محیطی را که SDK تنظیم کرده بود، حذف میکند و برنامههای Firebase را که ممکن است در صورت استفاده از SDK برای ایجاد پایگاه داده همزمان DataSnapshot
یا Firestore DocumentSnapshot
ایجاد شده باشند، حذف میکند.
test.cleanup();
نمونه های کامل را مرور کنید و بیشتر بدانید
می توانید نمونه های کامل را در مخزن Firebase GitHub مرور کنید.
- آزمایش Realtime Database و توابع HTTP در حالت آنلاین
- آزمایش Realtime Database و توابع HTTP در حالت آفلاین
برای کسب اطلاعات بیشتر، به مرجع API برای firebase-functions-test
مراجعه کنید.
این صفحه بهترین روشها و ابزارها را برای نوشتن تستهای واحد برای عملکردهای شما، مانند تستهایی که بخشی از سیستم یکپارچهسازی مداوم (CI) هستند، شرح میدهد. برای آسانتر کردن آزمایش، Firebase Firebase Test SDK برای Cloud Functions ارائه میکند. در npm به عنوان firebase-functions-test
توزیع میشود و یک SDK آزمایشی همراه با firebase-functions
است. Firebase Test SDK برای Cloud Functions :
- از راهاندازی و حذف مناسب برای تستهای شما مراقبت میکند، مانند تنظیم و غیرفعال کردن متغیرهای محیطی مورد نیاز
firebase-functions
. - داده های نمونه و زمینه رویداد را ایجاد می کند، به طوری که شما فقط باید فیلدهایی را که مربوط به آزمون شما هستند مشخص کنید.
تنظیم تست
با اجرای دستورات زیر در پوشه توابع خود، هم firebase-functions-test
و هم Mocha ، یک چارچوب آزمایشی را نصب کنید:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
سپس یک پوشه test
در داخل پوشه توابع ایجاد کنید، یک فایل جدید در داخل آن برای کد تست خود ایجاد کنید و نام آن را چیزی مانند index.test.js
بگذارید.
در نهایت، functions/package.json
را تغییر دهید تا موارد زیر را اضافه کنید:
"scripts": {
"test": "mocha --reporter spec"
}
هنگامی که تست ها را نوشتید، می توانید با اجرای npm test
در دایرکتوری توابع خود، آنها را اجرا کنید.
راه اندازی Firebase Test SDK برای Cloud Functions
دو راه برای استفاده از firebase-functions-test
وجود دارد:
- حالت آنلاین (توصیه میشود): تستهایی را بنویسید که با پروژه Firebase که به آزمایش اختصاص داده شده است، تعامل داشته باشند تا در واقع نوشتن پایگاه داده، ایجاد کاربر و غیره اتفاق بیفتد و کد تست شما بتواند نتایج را بررسی کند. این همچنین به این معنی است که سایر SDK های Google مورد استفاده در توابع شما نیز کار خواهند کرد.
- حالت آفلاین: تست های واحد siled و آفلاین را بدون عوارض جانبی بنویسید. این بدان معناست که هر فراخوانی متدی که با یک محصول Firebase تعامل دارد (مثلاً نوشتن در پایگاه داده یا ایجاد یک کاربر) باید stubbed شود. اگر دارای عملکردهای Cloud Firestore یا Realtime Database هستید، معمولاً استفاده از حالت آفلاین توصیه نمی شود، زیرا پیچیدگی کد آزمایشی شما را بسیار افزایش می دهد.
راه اندازی SDK در حالت آنلاین (توصیه می شود)
اگر میخواهید آزمایشهایی بنویسید که با یک پروژه آزمایشی تعامل دارند، باید مقادیر پیکربندی پروژه را که برای مقداردهی اولیه برنامه از طریق firebase-admin
مورد نیاز است و مسیر فایل کلید حساب سرویس را ارائه کنید.
برای دریافت مقادیر پیکربندی پروژه Firebase:
- تنظیمات پروژه خود را در کنسول Firebase باز کنید.
- در برنامه های شما، برنامه مورد نظر را انتخاب کنید.
در قسمت سمت راست، گزینه دانلود فایل پیکربندی برنامه های اپل و اندروید را انتخاب کنید.
برای برنامه های وب، Config را برای نمایش مقادیر پیکربندی انتخاب کنید.
برای ایجاد یک فایل کلید:
- صفحه حسابهای سرویس کنسول Google Cloud را باز کنید.
- حساب سرویس پیشفرض App Engine را انتخاب کنید و از منوی گزینهها در سمت راست برای انتخاب کلید ایجاد استفاده کنید.
- وقتی از شما خواسته شد، JSON را برای نوع کلید انتخاب کنید و روی ایجاد کلیک کنید.
پس از ذخیره فایل کلید، SDK را مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')({
databaseURL: 'https://my-project.firebaseio.com',
storageBucket: 'my-project.appspot.com',
projectId: 'my-project',
}, 'path/to/serviceAccountKey.json');
SDK را در حالت آفلاین راه اندازی کنید
اگر می خواهید تست های کاملا آفلاین بنویسید، می توانید SDK را بدون هیچ پارامتری مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
مسخره کردن مقادیر پیکربندی
اگر functions.config()
در کد توابع خود استفاده می کنید، می توانید مقادیر پیکربندی را مسخره کنید. برای مثال، اگر functions/index.js
حاوی کد زیر باشد:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
سپس میتوانید مقدار داخل فایل آزمایشی خود را به شکل زیر مسخره کنید:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
وارد کردن توابع شما
برای وارد کردن توابع خود، از require
برای وارد کردن فایل توابع اصلی خود به عنوان یک ماژول استفاده کنید. مطمئن شوید که این کار را فقط پس از مقداردهی اولیه firebase-functions-test
و مسخره کردن مقادیر پیکربندی انجام دهید.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
اگر firebase-functions-test
در حالت آفلاین مقداردهی اولیه کردید و در کد توابع خود admin.initializeApp()
دارید، باید قبل از وارد کردن توابع، آن را خرد کنید:
// If index.js calls admin.initializeApp at the top of the file, // we need to stub it out before requiring index.js. This is because the // functions will be executed as a part of the require process. // Here we stub admin.initializeApp to be a dummy function that doesn't do anything. adminInitStub = sinon.stub(admin, 'initializeApp'); // Now we can require index.js and save the exports inside a namespace called myFunctions. myFunctions = require('../index');
تست توابع پس زمینه (غیر HTTP).
فرآیند آزمایش توابع غیر HTTP شامل مراحل زیر است:
- تابعی را که می خواهید آزمایش کنید با روش
test.wrap
بپیچید - داده های آزمایشی را بسازید
- تابع پیچیده شده را با داده های آزمایشی که ساخته اید و هر فیلد زمینه رویدادی که می خواهید مشخص کنید فراخوانی کنید.
- در مورد رفتار اظهار نظر کنید.
ابتدا تابعی را که می خواهید آزمایش کنید بپیچید. فرض کنید یک تابع در functions/index.js
به نام makeUppercase
دارید که میخواهید آن را آزمایش کنید. موارد زیر را در functions/test/index.test.js
بنویسید
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
تابعی است که هنگام فراخوانی makeUppercase
فراخوانی می کند. wrapped
2 پارامتر می گیرد:
- داده (الزامی): داده هایی برای ارسال به
makeUppercase
. این به طور مستقیم با اولین پارامتر ارسال شده به تابعی که نوشتید مطابقت دارد.firebase-functions-test
روش هایی را برای ساخت داده های سفارشی یا داده های نمونه ارائه می دهد. - eventContextOptions (اختیاری): فیلدهایی از زمینه رویداد که می خواهید مشخص کنید. زمینه رویداد دومین پارامتری است که به کنترل کننده تابعی که نوشته اید ارسال می شود. اگر هنگام فراخوانی
wrapped
پارامترeventContextOptions
را وارد نکنید، یک زمینه رویداد همچنان با فیلدهای معقول ایجاد می شود. شما می توانید برخی از فیلدهای تولید شده را با مشخص کردن آنها در اینجا لغو کنید. توجه داشته باشید که فقط باید فیلدهایی را که میخواهید لغو شوند، وارد کنید. هر فیلدی که شما لغو نکرده اید ایجاد می شود.
const data = … // See next section for constructing test data
// Invoke the wrapped function without specifying the event context.
wrapped(data);
// Invoke the function, and specify params
wrapped(data, {
params: {
pushId: '234234'
}
});
// Invoke the function, and specify auth and auth Type (for real time database functions only)
wrapped(data, {
auth: {
uid: 'jckS2Q0'
},
authType: 'USER'
});
// Invoke the function, and specify all the fields that can be specified
wrapped(data, {
eventId: 'abc',
timestamp: '2018-03-23T17:27:17.099Z',
params: {
pushId: '234234'
},
auth: {
uid: 'jckS2Q0' // only for real time database functions
},
authType: 'USER' // only for real time database functions
});
ساخت داده های آزمایشی
اولین پارامتر یک تابع پیچیده، داده های آزمایشی است که تابع زیرین را با آن فراخوانی می کند. روش های مختلفی برای ساخت داده های آزمایشی وجود دارد.
استفاده از داده های سفارشی
firebase-functions-test
تعدادی توابع برای ساخت داده های مورد نیاز برای آزمایش توابع شما دارد. برای مثال، از test.firestore.makeDocumentSnapshot
برای ایجاد یک Firestore DocumentSnapshot
استفاده کنید. آرگومان اول داده است و آرگومان دوم مسیر مرجع کامل است و یک آرگومان سوم اختیاری برای سایر ویژگی های عکس فوری وجود دارد که می توانید مشخص کنید.
// Make snapshot
const snap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Call wrapped function with the snapshot
const wrapped = test.wrap(myFunctions.myFirestoreDeleteFunction);
wrapped(snap);
اگر در حال آزمایش یک تابع onUpdate
یا onWrite
هستید، باید دو عکس فوری ایجاد کنید: یکی برای حالت قبل و دیگری برای حالت بعد. سپس، می توانید از متد makeChange
برای ایجاد یک شی Change
با این عکس های فوری استفاده کنید.
// Make snapshot for state of database beforehand
const beforeSnap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Make snapshot for state of database after the change
const afterSnap = test.firestore.makeDocumentSnapshot({foo: 'faz'}, 'document/path');
const change = test.makeChange(beforeSnap, afterSnap);
// Call wrapped function with the Change object
const wrapped = test.wrap(myFunctions.myFirestoreUpdateFunction);
wrapped(change);
به مرجع API برای توابع مشابه برای همه انواع داده های دیگر مراجعه کنید.
با استفاده از داده های نمونه
اگر نیازی به سفارشی سازی داده های مورد استفاده در تست های خود ندارید، firebase-functions-test
روش هایی را برای تولید داده های نمونه برای هر نوع تابع ارائه می دهد.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
مرجع API را برای روشهایی برای دریافت نمونه دادهها برای هر نوع تابع ببینید.
استفاده از داده های خرد شده (برای حالت آفلاین)
اگر SDK را در حالت آفلاین مقداردهی اولیه کرده اید و در حال آزمایش عملکرد Cloud Firestore یا Realtime Database هستید، باید به جای ایجاد یک DocumentSnapshot
یا DataSnapshot
واقعی از یک شی ساده با خرد استفاده کنید.
فرض کنید در حال نوشتن یک آزمون واحد برای تابع زیر هستید:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
در داخل تابع، snap
دو بار استفاده می شود:
-
snap.val()
-
snap.ref.parent.child('uppercase').set(uppercase)
در کد تست، یک شیء ساده ایجاد کنید که در آن هر دو مسیر کد کار کنند و از Sinon برای Stub متدها استفاده کنید.
// The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true);
اظهار نظر
پس از مقداردهی اولیه SDK، بسته بندی توابع، و ساخت داده ها، می توانید توابع پیچیده شده را با داده های ساخته شده فراخوانی کنید و در مورد رفتار اظهار نظر کنید. برای بیان این ادعاها می توانید از کتابخانه ای مانند چای استفاده کنید.
اظهار نظر در حالت آنلاین
اگر Firebase Test SDK برای Cloud Functions در حالت آنلاین راهاندازی کرده باشید، میتوانید با استفاده از firebase-admin
SDK ادعا کنید که اقدامات مورد نظر (مانند نوشتن پایگاه داده) انجام شده است.
مثال زیر بیان می کند که "INPUT" در پایگاه داده پروژه آزمایشی نوشته شده است.
// Create a DataSnapshot with the value 'input' and the reference path 'messages/11111/original'. const snap = test.database.makeDataSnapshot('input', 'messages/11111/original'); // Wrap the makeUppercase function const wrapped = test.wrap(myFunctions.makeUppercase); // Call the wrapped function with the snapshot you constructed. return wrapped(snap).then(() => { // Read the value of the data at messages/11111/uppercase. Because `admin.initializeApp()` is // called in functions/index.js, there's already a Firebase app initialized. Otherwise, add // `admin.initializeApp()` before this line. return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => { // Assert that the value is the uppercased version of our input. assert.equal(createdSnap.val(), 'INPUT'); }); });
اظهار نظر در حالت آفلاین
می توانید در مورد مقدار بازگشتی مورد انتظار تابع اظهار نظر کنید:
const childParam = 'uppercase'; const setParam = 'INPUT'; // Stubs are objects that fake and/or record function calls. // These are excellent for verifying that functions have been called and to validate the // parameters passed to those functions. const childStub = sinon.stub(); const setStub = sinon.stub(); // The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true); // Wrap the makeUppercase function. const wrapped = test.wrap(myFunctions.makeUppercase); // Since we've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was // called with the parameters we expect, we assert that it indeed returned true. return assert.equal(wrapped(snap), true);
همچنین میتوانید از جاسوسهای Sinon برای تأیید اینکه متدهای خاصی فراخوانی شدهاند و با پارامترهایی که انتظار دارید استفاده کنید.
تست توابع HTTP
برای آزمایش توابع HTTP onCall، از همان رویکرد آزمایش توابع پسزمینه استفاده کنید.
اگر در حال آزمایش توابع HTTP onRequest هستید، باید از firebase-functions-test
استفاده کنید اگر:
- شما از
functions.config()
استفاده می کنید - عملکرد شما با یک پروژه Firebase یا سایر APIهای Google تعامل دارد و میخواهید از یک پروژه Firebase واقعی و اعتبار آن برای آزمایشهای خود استفاده کنید.
یک تابع onRequest HTTP دو پارامتر دارد: یک شی درخواست و یک شی پاسخ. در اینجا نحوه آزمایش تابع مثال addMessage()
آمده است:
- تابع تغییر مسیر را در شیء پاسخ لغو کنید، زیرا
sendMessage()
آن را فراخوانی می کند. - در تابع تغییر مسیر، از chai.assert برای کمک به اظهارنظر در مورد پارامترهایی که تابع تغییر مسیر باید با چه پارامترهایی فراخوانی شود، استفاده کنید:
// A fake request object, with req.query.text set to 'input' const req = { query: {text: 'input'} }; // A fake response object, with a stubbed redirect function which asserts that it is called // with parameters 303, 'new_ref'. const res = { redirect: (code, url) => { assert.equal(code, 303); assert.equal(url, 'new_ref'); done(); } }; // Invoke addMessage with our fake request and response objects. This will cause the // assertions in the response object to be evaluated. myFunctions.addMessage(req, res);
پاکسازی آزمایشی
در انتهای کد آزمایشی خود، تابع پاکسازی را فراخوانی کنید. این کار متغیرهای محیطی را که SDK تنظیم کرده بود، حذف میکند و برنامههای Firebase را که ممکن است در صورت استفاده از SDK برای ایجاد پایگاه داده همزمان DataSnapshot
یا Firestore DocumentSnapshot
ایجاد شده باشند، حذف میکند.
test.cleanup();
نمونه های کامل را مرور کنید و بیشتر بدانید
می توانید نمونه های کامل را در مخزن Firebase GitHub مرور کنید.
- آزمایش Realtime Database و توابع HTTP در حالت آنلاین
- آزمایش Realtime Database و توابع HTTP در حالت آفلاین
برای کسب اطلاعات بیشتر، به مرجع API برای firebase-functions-test
مراجعه کنید.
این صفحه بهترین روشها و ابزارها را برای نوشتن تستهای واحد برای عملکردهای شما، مانند تستهایی که بخشی از سیستم یکپارچهسازی مداوم (CI) هستند، شرح میدهد. برای آسانتر کردن آزمایش، Firebase Firebase Test SDK برای Cloud Functions ارائه میکند. در npm به عنوان firebase-functions-test
توزیع میشود و یک SDK آزمایشی همراه با firebase-functions
است. Firebase Test SDK برای Cloud Functions :
- از راهاندازی و حذف مناسب برای تستهای شما مراقبت میکند، مانند تنظیم و غیرفعال کردن متغیرهای محیطی مورد نیاز
firebase-functions
. - داده های نمونه و زمینه رویداد را ایجاد می کند، به طوری که شما فقط باید فیلدهایی را که مربوط به آزمون شما هستند مشخص کنید.
تنظیم تست
با اجرای دستورات زیر در پوشه توابع خود، هم firebase-functions-test
و هم Mocha ، یک چارچوب آزمایشی را نصب کنید:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
سپس یک پوشه test
در داخل پوشه توابع ایجاد کنید، یک فایل جدید در داخل آن برای کد تست خود ایجاد کنید و نام آن را چیزی مانند index.test.js
بگذارید.
در نهایت، functions/package.json
را تغییر دهید تا موارد زیر را اضافه کنید:
"scripts": {
"test": "mocha --reporter spec"
}
هنگامی که تست ها را نوشتید، می توانید با اجرای npm test
در دایرکتوری توابع خود، آنها را اجرا کنید.
راه اندازی Firebase Test SDK برای Cloud Functions
دو راه برای استفاده از firebase-functions-test
وجود دارد:
- حالت آنلاین (توصیه میشود): تستهایی را بنویسید که با پروژه Firebase که به آزمایش اختصاص داده شده است، تعامل داشته باشند تا در واقع نوشتن پایگاه داده، ایجاد کاربر و غیره اتفاق بیفتد و کد تست شما بتواند نتایج را بررسی کند. این همچنین به این معنی است که سایر SDK های Google مورد استفاده در توابع شما نیز کار خواهند کرد.
- حالت آفلاین: تست های واحد siled و آفلاین را بدون عوارض جانبی بنویسید. این بدان معناست که هر فراخوانی متدی که با یک محصول Firebase تعامل دارد (مثلاً نوشتن در پایگاه داده یا ایجاد یک کاربر) باید stubbed شود. اگر دارای عملکردهای Cloud Firestore یا Realtime Database هستید، معمولاً استفاده از حالت آفلاین توصیه نمی شود، زیرا پیچیدگی کد آزمایشی شما را بسیار افزایش می دهد.
راه اندازی SDK در حالت آنلاین (توصیه می شود)
اگر میخواهید آزمایشهایی بنویسید که با یک پروژه آزمایشی تعامل دارند، باید مقادیر پیکربندی پروژه را که برای مقداردهی اولیه برنامه از طریق firebase-admin
مورد نیاز است و مسیر فایل کلید حساب سرویس را ارائه کنید.
برای دریافت مقادیر پیکربندی پروژه Firebase:
- تنظیمات پروژه خود را در کنسول Firebase باز کنید.
- در برنامه های شما، برنامه مورد نظر را انتخاب کنید.
در قسمت سمت راست، گزینه دانلود فایل پیکربندی برنامه های اپل و اندروید را انتخاب کنید.
برای برنامه های وب، Config را برای نمایش مقادیر پیکربندی انتخاب کنید.
برای ایجاد یک فایل کلیدی:
- صفحه حسابهای سرویس کنسول Google Cloud را باز کنید.
- حساب سرویس پیشفرض App Engine را انتخاب کنید و از منوی گزینهها در سمت راست برای انتخاب کلید ایجاد استفاده کنید.
- وقتی از شما خواسته شد، JSON را برای نوع کلید انتخاب کنید و روی ایجاد کلیک کنید.
پس از ذخیره فایل کلید، SDK را مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')({
databaseURL: 'https://my-project.firebaseio.com',
storageBucket: 'my-project.appspot.com',
projectId: 'my-project',
}, 'path/to/serviceAccountKey.json');
SDK را در حالت آفلاین راه اندازی کنید
اگر می خواهید تست های کاملا آفلاین بنویسید، می توانید SDK را بدون هیچ پارامتری مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
مسخره کردن مقادیر پیکربندی
اگر functions.config()
در کد توابع خود استفاده می کنید، می توانید مقادیر پیکربندی را مسخره کنید. برای مثال، اگر functions/index.js
حاوی کد زیر باشد:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
سپس میتوانید مقدار داخل فایل آزمایشی خود را به شکل زیر مسخره کنید:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
وارد کردن توابع شما
برای وارد کردن توابع خود، از require
برای وارد کردن فایل توابع اصلی خود به عنوان یک ماژول استفاده کنید. مطمئن شوید که این کار را فقط پس از مقداردهی اولیه firebase-functions-test
و مسخره کردن مقادیر پیکربندی انجام دهید.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
اگر firebase-functions-test
در حالت آفلاین مقداردهی اولیه کردید و در کد توابع خود admin.initializeApp()
دارید، باید قبل از وارد کردن توابع، آن را خرد کنید:
// If index.js calls admin.initializeApp at the top of the file, // we need to stub it out before requiring index.js. This is because the // functions will be executed as a part of the require process. // Here we stub admin.initializeApp to be a dummy function that doesn't do anything. adminInitStub = sinon.stub(admin, 'initializeApp'); // Now we can require index.js and save the exports inside a namespace called myFunctions. myFunctions = require('../index');
تست توابع پس زمینه (غیر HTTP).
فرآیند آزمایش توابع غیر HTTP شامل مراحل زیر است:
- تابعی را که می خواهید آزمایش کنید با روش
test.wrap
بپیچید - داده های آزمایشی را بسازید
- تابع پیچیده شده را با داده های آزمایشی که ساخته اید و هر فیلد زمینه رویدادی که می خواهید مشخص کنید فراخوانی کنید.
- در مورد رفتار اظهار نظر کنید.
ابتدا تابعی را که می خواهید آزمایش کنید بپیچید. فرض کنید یک تابع در functions/index.js
به نام makeUppercase
دارید که میخواهید آن را آزمایش کنید. موارد زیر را در functions/test/index.test.js
بنویسید
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
تابعی است که هنگام فراخوانی makeUppercase
فراخوانی می کند. wrapped
2 پارامتر می گیرد:
- داده (الزامی): داده هایی برای ارسال به
makeUppercase
. این به طور مستقیم با اولین پارامتر ارسال شده به تابعی که نوشتید مطابقت دارد.firebase-functions-test
روش هایی را برای ساخت داده های سفارشی یا داده های نمونه ارائه می دهد. - eventContextOptions (اختیاری): فیلدهایی از زمینه رویداد که می خواهید مشخص کنید. زمینه رویداد دومین پارامتری است که به کنترل کننده تابعی که نوشته اید ارسال می شود. اگر هنگام فراخوانی
wrapped
پارامترeventContextOptions
را وارد نکنید، یک زمینه رویداد همچنان با فیلدهای معقول ایجاد می شود. شما می توانید برخی از فیلدهای تولید شده را با مشخص کردن آنها در اینجا لغو کنید. توجه داشته باشید که فقط باید فیلدهایی را که میخواهید لغو شوند، وارد کنید. هر فیلدی که شما لغو نکرده اید ایجاد می شود.
const data = … // See next section for constructing test data
// Invoke the wrapped function without specifying the event context.
wrapped(data);
// Invoke the function, and specify params
wrapped(data, {
params: {
pushId: '234234'
}
});
// Invoke the function, and specify auth and auth Type (for real time database functions only)
wrapped(data, {
auth: {
uid: 'jckS2Q0'
},
authType: 'USER'
});
// Invoke the function, and specify all the fields that can be specified
wrapped(data, {
eventId: 'abc',
timestamp: '2018-03-23T17:27:17.099Z',
params: {
pushId: '234234'
},
auth: {
uid: 'jckS2Q0' // only for real time database functions
},
authType: 'USER' // only for real time database functions
});
ساخت داده های آزمایشی
اولین پارامتر یک تابع پیچیده، داده های آزمایشی است که تابع زیرین را با آن فراخوانی می کند. روش های مختلفی برای ساخت داده های آزمایشی وجود دارد.
استفاده از داده های سفارشی
firebase-functions-test
تعدادی توابع برای ساخت داده های مورد نیاز برای آزمایش توابع شما دارد. برای مثال، از test.firestore.makeDocumentSnapshot
برای ایجاد یک Firestore DocumentSnapshot
استفاده کنید. آرگومان اول داده است و آرگومان دوم مسیر مرجع کامل است و یک آرگومان سوم اختیاری برای سایر ویژگی های عکس فوری وجود دارد که می توانید مشخص کنید.
// Make snapshot
const snap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Call wrapped function with the snapshot
const wrapped = test.wrap(myFunctions.myFirestoreDeleteFunction);
wrapped(snap);
اگر در حال آزمایش یک تابع onUpdate
یا onWrite
هستید، باید دو عکس فوری ایجاد کنید: یکی برای حالت قبل و دیگری برای حالت بعد. سپس، می توانید از متد makeChange
برای ایجاد یک شی Change
با این عکس های فوری استفاده کنید.
// Make snapshot for state of database beforehand
const beforeSnap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Make snapshot for state of database after the change
const afterSnap = test.firestore.makeDocumentSnapshot({foo: 'faz'}, 'document/path');
const change = test.makeChange(beforeSnap, afterSnap);
// Call wrapped function with the Change object
const wrapped = test.wrap(myFunctions.myFirestoreUpdateFunction);
wrapped(change);
به مرجع API برای توابع مشابه برای همه انواع داده های دیگر مراجعه کنید.
با استفاده از داده های نمونه
اگر نیازی به سفارشی سازی داده های مورد استفاده در تست های خود ندارید، firebase-functions-test
روش هایی را برای تولید داده های نمونه برای هر نوع تابع ارائه می دهد.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
مرجع API را برای روشهایی برای دریافت نمونه دادهها برای هر نوع تابع ببینید.
استفاده از داده های خرد شده (برای حالت آفلاین)
اگر SDK را در حالت آفلاین مقداردهی اولیه کرده اید و در حال آزمایش عملکرد Cloud Firestore یا Realtime Database هستید، باید به جای ایجاد یک DocumentSnapshot
یا DataSnapshot
واقعی از یک شی ساده با خرد استفاده کنید.
فرض کنید در حال نوشتن یک آزمون واحد برای تابع زیر هستید:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
در داخل تابع، snap
دو بار استفاده می شود:
-
snap.val()
-
snap.ref.parent.child('uppercase').set(uppercase)
در کد تست، یک شیء ساده ایجاد کنید که در آن هر دو مسیر کد کار کنند و از Sinon برای Stub متدها استفاده کنید.
// The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true);
اظهار نظر
پس از مقداردهی اولیه SDK، بسته بندی توابع، و ساخت داده ها، می توانید توابع پیچیده شده را با داده های ساخته شده فراخوانی کنید و در مورد رفتار اظهار نظر کنید. برای بیان این ادعاها می توانید از کتابخانه ای مانند چای استفاده کنید.
اظهار نظر در حالت آنلاین
اگر Firebase Test SDK برای Cloud Functions در حالت آنلاین راهاندازی کرده باشید، میتوانید با استفاده از firebase-admin
SDK ادعا کنید که اقدامات مورد نظر (مانند نوشتن پایگاه داده) انجام شده است.
مثال زیر بیان می کند که "INPUT" در پایگاه داده پروژه آزمایشی نوشته شده است.
// Create a DataSnapshot with the value 'input' and the reference path 'messages/11111/original'. const snap = test.database.makeDataSnapshot('input', 'messages/11111/original'); // Wrap the makeUppercase function const wrapped = test.wrap(myFunctions.makeUppercase); // Call the wrapped function with the snapshot you constructed. return wrapped(snap).then(() => { // Read the value of the data at messages/11111/uppercase. Because `admin.initializeApp()` is // called in functions/index.js, there's already a Firebase app initialized. Otherwise, add // `admin.initializeApp()` before this line. return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => { // Assert that the value is the uppercased version of our input. assert.equal(createdSnap.val(), 'INPUT'); }); });
اظهار نظر در حالت آفلاین
می توانید در مورد مقدار بازگشتی مورد انتظار تابع اظهار نظر کنید:
const childParam = 'uppercase'; const setParam = 'INPUT'; // Stubs are objects that fake and/or record function calls. // These are excellent for verifying that functions have been called and to validate the // parameters passed to those functions. const childStub = sinon.stub(); const setStub = sinon.stub(); // The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true); // Wrap the makeUppercase function. const wrapped = test.wrap(myFunctions.makeUppercase); // Since we've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was // called with the parameters we expect, we assert that it indeed returned true. return assert.equal(wrapped(snap), true);
همچنین میتوانید از جاسوسهای Sinon برای تأیید اینکه متدهای خاصی فراخوانی شدهاند و با پارامترهایی که انتظار دارید استفاده کنید.
تست توابع HTTP
برای آزمایش توابع HTTP onCall، از همان رویکرد آزمایش توابع پسزمینه استفاده کنید.
اگر در حال آزمایش توابع HTTP onRequest هستید، باید از firebase-functions-test
استفاده کنید اگر:
- شما از
functions.config()
استفاده می کنید - عملکرد شما با یک پروژه Firebase یا سایر APIهای Google تعامل دارد و میخواهید از یک پروژه Firebase واقعی و اعتبار آن برای آزمایشهای خود استفاده کنید.
یک تابع onRequest HTTP دو پارامتر دارد: یک شی درخواست و یک شی پاسخ. در اینجا نحوه آزمایش تابع مثال addMessage()
آمده است:
- تابع تغییر مسیر را در شیء پاسخ لغو کنید، زیرا
sendMessage()
آن را فراخوانی می کند. - در تابع تغییر مسیر، از chai.assert برای کمک به اظهارنظر در مورد پارامترهایی که تابع تغییر مسیر باید با چه پارامترهایی فراخوانی شود، استفاده کنید:
// A fake request object, with req.query.text set to 'input' const req = { query: {text: 'input'} }; // A fake response object, with a stubbed redirect function which asserts that it is called // with parameters 303, 'new_ref'. const res = { redirect: (code, url) => { assert.equal(code, 303); assert.equal(url, 'new_ref'); done(); } }; // Invoke addMessage with our fake request and response objects. This will cause the // assertions in the response object to be evaluated. myFunctions.addMessage(req, res);
پاکسازی آزمایشی
در انتهای کد آزمایشی خود، تابع پاکسازی را فراخوانی کنید. این کار متغیرهای محیطی را که SDK تنظیم کرده بود، حذف میکند و برنامههای Firebase را که ممکن است در صورت استفاده از SDK برای ایجاد پایگاه داده همزمان DataSnapshot
یا Firestore DocumentSnapshot
ایجاد شده باشند، حذف میکند.
test.cleanup();
نمونه های کامل را مرور کنید و بیشتر بدانید
می توانید نمونه های کامل را در مخزن Firebase GitHub مرور کنید.
- آزمایش Realtime Database و توابع HTTP در حالت آنلاین
- آزمایش Realtime Database و توابع HTTP در حالت آفلاین
برای کسب اطلاعات بیشتر، به مرجع API برای firebase-functions-test
مراجعه کنید.
این صفحه بهترین روشها و ابزارها را برای نوشتن تستهای واحد برای عملکردهای شما، مانند تستهایی که بخشی از سیستم یکپارچهسازی مداوم (CI) هستند، شرح میدهد. برای آسانتر کردن آزمایش، Firebase Firebase Test SDK برای Cloud Functions ارائه میکند. در npm به عنوان firebase-functions-test
توزیع میشود و یک SDK آزمایشی همراه با firebase-functions
است. Firebase Test SDK برای Cloud Functions :
- از راهاندازی و حذف مناسب برای تستهای شما مراقبت میکند، مانند تنظیم و غیرفعال کردن متغیرهای محیطی مورد نیاز
firebase-functions
. - داده های نمونه و زمینه رویداد را ایجاد می کند، به طوری که شما فقط باید فیلدهایی را که مربوط به آزمون شما هستند مشخص کنید.
تنظیم تست
با اجرای دستورات زیر در پوشه توابع خود، هم firebase-functions-test
و هم Mocha ، یک چارچوب آزمایشی را نصب کنید:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
سپس یک پوشه test
در داخل پوشه توابع ایجاد کنید، یک فایل جدید در داخل آن برای کد تست خود ایجاد کنید و نام آن را چیزی مانند index.test.js
بگذارید.
در نهایت، functions/package.json
را تغییر دهید تا موارد زیر را اضافه کنید:
"scripts": {
"test": "mocha --reporter spec"
}
هنگامی که تست ها را نوشتید، می توانید با اجرای npm test
در دایرکتوری توابع خود، آنها را اجرا کنید.
راه اندازی Firebase Test SDK برای Cloud Functions
دو راه برای استفاده از firebase-functions-test
وجود دارد:
- حالت آنلاین (توصیه میشود): تستهایی را بنویسید که با پروژه Firebase که به آزمایش اختصاص داده شده است، تعامل داشته باشند تا در واقع نوشتن پایگاه داده، ایجاد کاربر و غیره اتفاق بیفتد و کد تست شما بتواند نتایج را بررسی کند. این همچنین به این معنی است که سایر SDK های Google مورد استفاده در توابع شما نیز کار خواهند کرد.
- حالت آفلاین: تست های واحد siled و آفلاین را بدون عوارض جانبی بنویسید. این بدان معناست که هر فراخوانی متدی که با یک محصول Firebase تعامل دارد (مثلاً نوشتن در پایگاه داده یا ایجاد یک کاربر) باید stubbed شود. اگر دارای عملکردهای Cloud Firestore یا Realtime Database هستید، معمولاً استفاده از حالت آفلاین توصیه نمی شود، زیرا پیچیدگی کد آزمایشی شما را بسیار افزایش می دهد.
راه اندازی SDK در حالت آنلاین (توصیه می شود)
اگر میخواهید آزمایشهایی بنویسید که با یک پروژه آزمایشی تعامل دارند، باید مقادیر پیکربندی پروژه را که برای مقداردهی اولیه برنامه از طریق firebase-admin
مورد نیاز است و مسیر فایل کلید حساب سرویس را ارائه کنید.
برای دریافت مقادیر پیکربندی پروژه Firebase:
- تنظیمات پروژه خود را در کنسول Firebase باز کنید.
- در برنامه های شما، برنامه مورد نظر را انتخاب کنید.
در قسمت سمت راست، گزینه دانلود فایل پیکربندی برنامه های اپل و اندروید را انتخاب کنید.
برای برنامه های وب، Config را برای نمایش مقادیر پیکربندی انتخاب کنید.
برای ایجاد یک فایل کلیدی:
- صفحه حسابهای سرویس کنسول Google Cloud را باز کنید.
- حساب سرویس پیشفرض App Engine را انتخاب کنید و از منوی گزینهها در سمت راست برای انتخاب کلید ایجاد استفاده کنید.
- وقتی از شما خواسته شد، JSON را برای نوع کلید انتخاب کنید و روی ایجاد کلیک کنید.
پس از ذخیره فایل کلید، SDK را مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')({
databaseURL: 'https://my-project.firebaseio.com',
storageBucket: 'my-project.appspot.com',
projectId: 'my-project',
}, 'path/to/serviceAccountKey.json');
SDK را در حالت آفلاین راه اندازی کنید
اگر می خواهید تست های کاملا آفلاین بنویسید، می توانید SDK را بدون هیچ پارامتری مقداردهی اولیه کنید:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
مسخره کردن مقادیر پیکربندی
اگر functions.config()
در کد توابع خود استفاده می کنید، می توانید مقادیر پیکربندی را مسخره کنید. برای مثال، اگر functions/index.js
حاوی کد زیر باشد:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
سپس می توانید مقدار موجود در پرونده تست خود را مانند آن مسخره کنید:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
وارد کردن توابع خود
برای وارد کردن توابع خود ، برای وارد کردن پرونده اصلی توابع خود به عنوان ماژول require
کنید. حتماً این کار را فقط پس از اولیه سازی firebase-functions-test
و مقادیر پیکربندی مسخره کنید.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
اگر firebase-functions-test
در حالت آفلاین قرار داده اید و در کد توابع خود admin.initializeApp()
دارید ، پس باید قبل از وارد کردن توابع خود ، آن را خرد کنید:
// If index.js calls admin.initializeApp at the top of the file, // we need to stub it out before requiring index.js. This is because the // functions will be executed as a part of the require process. // Here we stub admin.initializeApp to be a dummy function that doesn't do anything. adminInitStub = sinon.stub(admin, 'initializeApp'); // Now we can require index.js and save the exports inside a namespace called myFunctions. myFunctions = require('../index');
توابع آزمایش پس زمینه (غیر HTTP)
فرآیند آزمایش توابع غیر HTTP شامل مراحل زیر است:
- عملکردی را که می خواهید با روش
test.wrap
تست کنید بپیچید - ساخت داده های آزمون
- از عملکرد بسته بندی شده با داده های آزمون که ساخته اید و هر زمینه زمینه رویداد را که می خواهید مشخص کنید ، فراخوانی کنید.
- در مورد رفتار ادعا کنید.
ابتدا عملکردی را که می خواهید آزمایش کنید بپیچید. بیایید بگوییم که شما یک عملکرد در functions/index.js
به نام makeUppercase
دارید که می خواهید آزمایش کنید. موارد زیر را در functions/test/index.test.js
بنویسید
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
تابعی است که هنگام فراخوانی از makeUppercase
فراخوانی می کند. wrapped
شده 2 پارامتر:
- داده ها (مورد نیاز): داده های ارسال به
makeUppercase
. این مستقیماً با اولین پارامتر ارسال شده به کنترل کننده عملکردی که نوشتید مطابقت دارد.firebase-functions-test
روش هایی را برای ساخت داده های سفارشی یا داده های مثال ارائه می دهد. - EventContextOptions (اختیاری): زمینه هایی از زمینه رویداد که می خواهید مشخص کنید. زمینه رویداد دومین پارامتر ارسال شده به کنترل کننده عملکردی است که شما نوشتید. اگر هنگام فراخوانی
wrapped
، یک پارامترeventContextOptions
را درج نکنید ، هنوز یک زمینه رویداد با زمینه های معقول ایجاد می شود. با مشخص کردن آنها در اینجا می توانید برخی از زمینه های تولید شده را نادیده بگیرید. توجه داشته باشید که شما فقط باید زمینه هایی را که می خواهید نادیده بگیرید ، درج کنید. هر زمینه ای که شما نادیده نگرفتید تولید می شود.
const data = … // See next section for constructing test data
// Invoke the wrapped function without specifying the event context.
wrapped(data);
// Invoke the function, and specify params
wrapped(data, {
params: {
pushId: '234234'
}
});
// Invoke the function, and specify auth and auth Type (for real time database functions only)
wrapped(data, {
auth: {
uid: 'jckS2Q0'
},
authType: 'USER'
});
// Invoke the function, and specify all the fields that can be specified
wrapped(data, {
eventId: 'abc',
timestamp: '2018-03-23T17:27:17.099Z',
params: {
pushId: '234234'
},
auth: {
uid: 'jckS2Q0' // only for real time database functions
},
authType: 'USER' // only for real time database functions
});
ساخت داده های آزمون
اولین پارامتر یک تابع بسته بندی شده ، داده های آزمون برای استناد به عملکرد زیرین است. چندین روش برای ساخت داده های آزمون وجود دارد.
با استفاده از داده های سفارشی
firebase-functions-test
دارای چندین کارکرد برای ساخت داده های مورد نیاز برای آزمایش توابع شما است. به عنوان مثال ، از test.firestore.makeDocumentSnapshot
برای ایجاد یک DocumentSnapshot
Firestore استفاده کنید. آرگومان اول داده ها است و آرگومان دوم مسیر مرجع کامل است و یک آرگومان سوم اختیاری برای سایر خصوصیات عکس فوری که می توانید مشخص کنید وجود دارد.
// Make snapshot
const snap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Call wrapped function with the snapshot
const wrapped = test.wrap(myFunctions.myFirestoreDeleteFunction);
wrapped(snap);
اگر در حال آزمایش یک عملکرد onUpdate
یا onWrite
هستید ، باید دو عکس فوری ایجاد کنید: یکی برای حالت قبل و دیگری برای حالت بعد. سپس ، می توانید از روش makeChange
برای ایجاد یک شیء Change
با این عکس های فوری استفاده کنید.
// Make snapshot for state of database beforehand
const beforeSnap = test.firestore.makeDocumentSnapshot({foo: 'bar'}, 'document/path');
// Make snapshot for state of database after the change
const afterSnap = test.firestore.makeDocumentSnapshot({foo: 'faz'}, 'document/path');
const change = test.makeChange(beforeSnap, afterSnap);
// Call wrapped function with the Change object
const wrapped = test.wrap(myFunctions.myFirestoreUpdateFunction);
wrapped(change);
برای توابع مشابه برای سایر انواع داده ها ، به مرجع API مراجعه کنید.
با استفاده از داده های مثال
اگر نیازی به سفارشی کردن داده های مورد استفاده در تست های خود ندارید ، firebase-functions-test
روش هایی را برای تولید داده های مثال برای هر نوع عملکرد ارائه می دهد.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
برای دریافت داده های مثال برای هر نوع عملکرد ، به مرجع API مراجعه کنید.
استفاده از داده های خرد شده (برای حالت آفلاین)
اگر SDK را در حالت آفلاین قرار داده اید و در حال آزمایش یک Cloud Firestore یا Realtime Database هستید ، باید به جای ایجاد یک DocumentSnapshot
یا DataSnapshot
، از یک شیء ساده با خردی استفاده کنید.
بیایید بگوییم که شما برای عملکرد زیر یک آزمون واحد را می نویسید:
// Listens for new messages added to /messages/:pushId/original and creates an // uppercase version of the message to /messages/:pushId/uppercase exports.makeUppercase = functions.database.ref('/messages/{pushId}/original') .onCreate((snapshot, context) => { // Grab the current value of what was written to the Realtime Database. const original = snapshot.val(); functions.logger.log('Uppercasing', context.params.pushId, original); const uppercase = original.toUpperCase(); // You must return a Promise when performing asynchronous tasks inside a Functions such as // writing to the Firebase Realtime Database. // Setting an "uppercase" sibling in the Realtime Database returns a Promise. return snapshot.ref.parent.child('uppercase').set(uppercase); });
در داخل عملکرد ، snap
دو بار استفاده می شود:
-
snap.val()
-
snap.ref.parent.child('uppercase').set(uppercase)
در کد آزمون ، یک شیء ساده ایجاد کنید که در آن هر دو مسیر کد کار کنند و از Sinon برای خرد کردن روش ها استفاده کنید.
// The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true);
ادعاها
پس از اولیه سازی SDK ، بسته بندی توابع و ساخت داده ها ، می توانید توابع پیچیده شده را با داده های ساخته شده فراخوانی کرده و در مورد رفتار ادعایی کنید. برای بیان این ادعاها می توانید از کتابخانه ای مانند چای استفاده کنید.
ادعاها در حالت آنلاین
اگر Firebase Test SDK برای Cloud Functions در حالت آنلاین تنظیم کردید ، می توانید ادعا کنید که اقدامات مورد نظر (مانند نوشتن پایگاه داده) با استفاده از SDK firebase-admin
انجام شده است.
مثال زیر ادعا می کند که "ورودی" در پایگاه داده پروژه آزمون نوشته شده است.
// Create a DataSnapshot with the value 'input' and the reference path 'messages/11111/original'. const snap = test.database.makeDataSnapshot('input', 'messages/11111/original'); // Wrap the makeUppercase function const wrapped = test.wrap(myFunctions.makeUppercase); // Call the wrapped function with the snapshot you constructed. return wrapped(snap).then(() => { // Read the value of the data at messages/11111/uppercase. Because `admin.initializeApp()` is // called in functions/index.js, there's already a Firebase app initialized. Otherwise, add // `admin.initializeApp()` before this line. return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => { // Assert that the value is the uppercased version of our input. assert.equal(createdSnap.val(), 'INPUT'); }); });
بیان ادعاها در حالت آفلاین
می توانید در مورد مقدار بازده مورد انتظار عملکرد ادعا کنید:
const childParam = 'uppercase'; const setParam = 'INPUT'; // Stubs are objects that fake and/or record function calls. // These are excellent for verifying that functions have been called and to validate the // parameters passed to those functions. const childStub = sinon.stub(); const setStub = sinon.stub(); // The following lines creates a fake snapshot, 'snap', which returns 'input' when snap.val() is called, // and returns true when snap.ref.parent.child('uppercase').set('INPUT') is called. const snap = { val: () => 'input', ref: { parent: { child: childStub, } } }; childStub.withArgs(childParam).returns({ set: setStub }); setStub.withArgs(setParam).returns(true); // Wrap the makeUppercase function. const wrapped = test.wrap(myFunctions.makeUppercase); // Since we've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was // called with the parameters we expect, we assert that it indeed returned true. return assert.equal(wrapped(snap), true);
همچنین می توانید از Sinon Spies استفاده کنید تا ادعا کنید که روش های خاصی فراخوانی شده است و با پارامترهایی که انتظار دارید.
آزمایش توابع HTTP
برای آزمایش توابع HTTP ONCALL ، از همان رویکرد آزمایشات پس زمینه استفاده کنید.
اگر در حال آزمایش توابع HTTP OnRequest هستید ، باید از firebase-functions-test
استفاده کنید اگر:
- شما
functions.config()
- عملکرد شما با یک پروژه Firebase یا سایر API های Google در تعامل است و می خواهید از یک پروژه Firebase واقعی و اعتبار آن برای آزمایشات خود استفاده کنید.
یک تابع HTTP OnRequest دو پارامتر می گیرد: یک شی درخواست و یک شی پاسخ. در اینجا نحوه تست عملکرد مثال addMessage()
آورده شده است:
- عملکرد تغییر مسیر را در شیء پاسخ نادیده بگیرید ، زیرا
sendMessage()
آن را صدا می کند. - در عملکرد تغییر مسیر ، از chai.assert استفاده کنید تا در مورد اینکه پارامترهای عملکرد تغییر مسیر را باید با آنها بیان کنید ، کمک کنید:
// A fake request object, with req.query.text set to 'input' const req = { query: {text: 'input'} }; // A fake response object, with a stubbed redirect function which asserts that it is called // with parameters 303, 'new_ref'. const res = { redirect: (code, url) => { assert.equal(code, 303); assert.equal(url, 'new_ref'); done(); } }; // Invoke addMessage with our fake request and response objects. This will cause the // assertions in the response object to be evaluated. myFunctions.addMessage(req, res);
پاکسازی تست
در انتهای کد تست خود ، با عملکرد پاکسازی تماس بگیرید. این متغیرهای محیطی را که SDK هنگام تنظیم تنظیم شده است ، تنظیم می کند و برنامه های Firebase را که ممکن است ایجاد شده باشد حذف می کند اگر از SDK برای ایجاد یک پایگاه DataSnapshot
پایگاه داده در زمان واقعی یا DocumentSnapshot
استفاده کنید.
test.cleanup();
مثالهای کامل را مرور کنید و بیشتر بدانید
می توانید مثالهای کامل را در مخزن GitHub Firebase مرور کنید.
- آزمایش Realtime Database و توابع HTTP در حالت آنلاین
- آزمایش Realtime Database و توابع HTTP در حالت آفلاین
برای کسب اطلاعات بیشتر ، به مرجع API برای firebase-functions-test
مراجعه کنید.