এই পৃষ্ঠায় আপনার ফাংশনের জন্য ইউনিট টেস্ট লেখার পেশাদার পদ্ধতি ও টুল সম্পর্কে বর্ণনা করা হয়েছে।
যেমন, এমন টেস্ট যা কন্টিনিউয়াস ইন্টিগ্রেশন (CI)
সিস্টেমের অংশ হতে পারে। টেস্টিং আরও সহজ করতে, Firebase Firebase Test SDK-এর জন্য Cloud Functions প্রদান করে। এটি
npm-এ firebase-functions-test হিসেবে ডিস্ট্রিবিউট করা হয় এবং এটি firebase-functions-এর
কম্প্যানিয়ন টেস্ট SDK. Cloud Functions-এর জন্য Firebase Test SDK:
- আপনার পরীক্ষার জন্য উপযুক্ত সেট-আপ ও টিয়ারডাউন করে, যেমন
firebase-functions-এর প্রয়োজনীয় এনভায়রনমেন্ট ভেরিয়েবল সেট ও আনসেট করা। - নমুনা ডেটা ও ইভেন্ট প্রসঙ্গ তৈরি করে, যাতে আপনাকে শুধু পরীক্ষার সাথে প্রাসঙ্গিক ফিল্ড উল্লেখ করতে হয়।
টেস্ট সেট-আপ
আপনার ফাংশন ফোল্ডারে নিম্নলিখিত কমান্ড চালিয়ে firebase-functions-test ও Jest, দুটিই ইনস্টল করুন, এটি হল
টেস্টিং ফ্রেমওয়ার্ক:
npm install --save-dev firebase-functions-test
npm install --save-dev jest
এরপর, functions ফোল্ডারের মধ্যে একটি test ফোল্ডার তৈরি করুন, আপনার টেস্ট কোডের জন্য এর মধ্যে একটি নতুন ফাইল তৈরি করুন
এবং index.test.js-এর মতো কোনও নাম দিন।
সবশেষে, নিম্নলিখিত বিষয়গুলি যোগ করতে functions/package.json পরিবর্তন করুন:
"scripts": {
"test": "jest"
}
টেস্ট লেখা হয়ে গেলে, আপনার ফাংশন ডিরেক্টরির মধ্যে npm test রান করে
আপনি সেগুলি রান করতে পারবেন।
Cloud Functions-এর জন্য Firebase Test SDK শুরু করা হচ্ছে
firebase-functions-test ব্যবহার করার দুটি উপায় আছে:
- অনলাইন মোড (সাজেস্ট করা): এমন টেস্ট লিখুন যা টেস্ট করার জন্য নির্দিষ্ট Firebase প্রোজেক্টের সাথে ইন্টার্যাক্ট করে, যাতে ডেটাবেস লেখা, ব্যবহারকারী তৈরি করা ইত্যাদি আসলে হয় এবং আপনার টেস্ট কোড ফলাফল পরিদর্শন করতে পারে। এর অর্থ হল, আপনার ফাংশনে ব্যবহৃত অন্যান্য Google SDK-ও কাজ করবে।
- অফলাইন মোড: কোনও পার্শ্বপ্রতিক্রিয়া ছাড়াই আলাদা আলাদা ও অফলাইন ইউনিট টেস্ট লিখুন। এর অর্থ হল, Firebase প্রোডাক্টের সাথে ইন্টার্যাক্ট করে এমন যেকোনও মেথড কল (যেমন, ডেটাবেসে লেখা বা ব্যবহারকারী তৈরি করা) স্টাব করতে হবে। আপনার কাছে Cloud Firestore বা Realtime Database ফাংশন থাকলে, সাধারণত অফলাইন মোড ব্যবহার করার পরামর্শ দেওয়া হয় না, কারণ এটি আপনার টেস্ট কোডের জটিলতা অনেক বাড়িয়ে দেয়।
অনলাইন মোডে SDK ইনিশিয়ালাইজ করুন (সাজেস্ট করা)
আপনি যদি এমন টেস্ট লিখতে চান যা টেস্ট প্রোজেক্টের সাথে ইন্টার্যাক্ট করে, তাহলে আপনাকে
firebase-admin-এর মাধ্যমে অ্যাপ ইনিশিয়ালাইজ করার জন্য প্রয়োজনীয় Firebase কনফিগারেশন ভ্যালু
এবং সার্ভিস অ্যাকাউন্ট কী ফাইলের পাথ দিতে হবে।
আপনার Firebase কনফিগারেশন ভ্যালু পেতে:
Firebase কনসোলে গিয়ে
সেটিংস > সাধারণ পৃষ্ঠা দেখুন।আপনার অ্যাপ কার্ডে স্ক্রল করে যান এবং কাঙ্ক্ষিত অ্যাপটি বেছে নিন।
আপনার Firebase কনফিগারেশন পান:
Apple ও Android অ্যাপের জন্য, কনফিগারেশন ফাইল ডাউনলোড করার বিকল্প বেছে নিন।
ওয়েব অ্যাপের জন্য, কনফিগারেশন ভ্যালু দেখাতে কনফিগার করুন বিকল্প বেছে নিন।
কী ফাইল তৈরি করতে:
Google Cloud কনসোলে, পরিষেবা অ্যাকাউন্ট প্যানে যান।
App Engine ডিফল্ট পরিষেবা অ্যাকাউন্ট বেছে নিন এবং কী তৈরি করুন বেছে নিতে ডানদিকে বিকল্প মেনু ব্যবহার করুন।
প্রম্পট করা হলে, কী ধরনের জন্য JSON বেছে নিন এবং তৈরি করুন বিকল্পে ক্লিক করুন।
কী ফাইল সেভ করার পরে, SDK ইনিশিয়ালাইজ করুন:
// At the top of test/index.test.js
// Make sure to use values from your actual Firebase configuration
const test = require('firebase-functions-test')({
databaseURL: 'https://PROJECT_ID.firebaseio.com',
storageBucket: 'PROJECT_ID.firebasestorage.app ',
projectId: 'PROJECT_ID',
}, '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() থাকে, তাহলে ফাংশন ইমপোর্ট করার আগে
আপনাকে এটি স্টাব করতে হবে। আপনার টেস্ট ফাইলে, firebase-admin as
admin প্রয়োজন, তারপর initializeApp()-এর জায়গায় Jest মক ব্যবহার করুন:
// If initializeApp() is called in index.js, we mock it out before requiring index.js adminInitStub = jest.spyOn(admin, 'initializeApp').mockImplementation(() => {}); // 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
দুটি প্যারামিটার নেয়:
- data (প্রয়োজনীয়):
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 ফাংশন পরীক্ষা করলে, আপনাকে
দুটি স্ন্যাপশট তৈরি করতে হবে: একটি আগের অবস্থা এবং একটি পরের অবস্থা। তারপর, আপনি এইসব স্ন্যাপশট দিয়ে Change অবজেক্ট তৈরি করতে makeChange পদ্ধতি ব্যবহার
করতে পারবেন।
// 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)
টেস্ট কোডে, এমন একটি সাধারণ অবজেক্ট তৈরি করুন যেখানে এই দুটি কোড পাথই কাজ করবে, এবং মেথড স্টাব করার জন্য Jest মক ফাংশন ব্যবহার করুন।
// The following lines create 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, } } };
দাবি করা
SDK ইনিশিয়ালাইজ করা, ফাংশন র্যাপ করা এবং ডেটা কনস্ট্রাক্ট করার পরে, আপনি
কনস্ট্রাক্ট করা ডেটা দিয়ে র্যাপ করা ফাংশন ইনভোক করতে এবং আচরণ সম্পর্কে অ্যাসারশন
করতে পারবেন। এইসব অ্যাসার্শন তৈরি করতে আপনি Jest-এর expect
ব্যবহার করতে পারবেন।
অনলাইন মোডে দাবি করা
আপনি যদি অনলাইন মোডে Cloud Functions-এর জন্য Firebase Test SDK ইনিশিয়ালাইজ করে থাকেন, তাহলে আপনি
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. return admin.database().ref('messages/11111/uppercase').once('value').then((createdSnap) => { // Assert that the value is the uppercased version of our input. expect(createdSnap.val()).toBe('INPUT'); }); });
অফলাইন মোডে দাবি করা
ফাংশনের প্রত্যাশিত রিটার্ন ভ্যালু সম্পর্কে আপনি অ্যাসার্শন করতে পারেন:
const childParam = 'uppercase'; const setParam = 'INPUT'; // Spies/mocks 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 setStub = jest.fn().mockImplementation((val) => val === setParam ? true : undefined); const childStub = jest.fn().mockImplementation((path) => path === childParam ? { set: setStub } : undefined); // The following lines create 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, } } }; // Wrap the makeUppercase function. const wrapped = test.wrap(myFunctions.makeUppercase); // Since we've mocked 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 wrapped(snap).then(makeUppercaseResult => { expect(makeUppercaseResult).toBe(true); });
এছাড়াও, আপনি Jest মক ফাংশন ব্যবহার করে নিশ্চিত করতে পারেন যে নির্দিষ্ট পদ্ধতি কল করা হয়েছে এবং আপনার প্রত্যাশিত প্যারামিটার সহ।
HTTP ফাংশন পরীক্ষা করা
HTTP onCall ফাংশন পরীক্ষা করতে, ব্যাকগ্রাউন্ড ফাংশন পরীক্ষা করার মতো একই পদ্ধতি ব্যবহার করুন।
আপনি HTTP onRequest ফাংশন পরীক্ষা করলে, আপনাকে
firebase-functions-test ব্যবহার করতে হবে যদি:
- আপনি
functions.config()ব্যবহার করেন - আপনার ফাংশন Firebase প্রোজেক্ট বা অন্যান্য Google API-এর সাথে ইন্টার্যাক্ট করে এবং আপনি নিজের পরীক্ষার জন্য আসল Firebase প্রোজেক্ট ও এর ক্রেডেনশিয়াল ব্যবহার করতে চান।
HTTP onRequest ফাংশন দুটি প্যারামিটার নেয়: একটি অনুরোধ অবজেক্ট এবং একটি উত্তর
অবজেক্ট। আপনি কীভাবে addMessage() উদাহরণ ফাংশন পরীক্ষা করতে পারেন তা এখানে দেওয়া হল:
স্টাব
admin.database(), কারণaddMessage()Realtime Database-এ পুশ করে। অফলাইন মোডে আপনিinitializeApp()স্টাব করেছেন, তাই Admin SDK ব্যবহার করার জন্য কোনও Firebase অ্যাপ নেই এবং আসলadmin.database()The default Firebase app does not exist-এর সাথে কাজ করে না:const pushStub = jest.fn().mockResolvedValue({ ref: 'new_ref' }); const refStub = jest.fn().mockReturnValue({ push: pushStub }); Object.defineProperty(admin, 'database', { configurable: true, writable: true, value: jest.fn().mockReturnValue({ ref: refStub }), });addMessage()এটি কল করে বলে, রেসপন্স অবজেক্টে রিডাইরেক্ট ফাংশনকে ওভাররাইড করুন।রিডাইরেক্ট ফাংশনের মধ্যে, Jest-এর
expectব্যবহার করে রিডাইরেক্ট ফাংশন কোন প্যারামিটার দিয়ে কল করা উচিত সেই সম্পর্কে অ্যাসারশন করুন:
// 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) => { expect(code).toBe(303); expect(url).toBe('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 চালু করার সময় SDK-এর সেট করা এনভায়রনমেন্ট ভেরিয়েবল আনসেট করে
এবং আপনি যদি SDK ব্যবহার করে রিয়েল
টাইম ডেটাবেস DataSnapshot বা Firestore DocumentSnapshot তৈরি করে থাকেন, তাহলে তৈরি করা Firebase অ্যাপ মুছে দেয়।
test.cleanup();
সম্পূর্ণ উদাহরণ পর্যালোচনা করুন এবং আরও জানুন
Firebase GitHub রিপোজিটরিতে আপনি সম্পূর্ণ উদাহরণ পর্যালোচনা করতে পারবেন।
- অনলাইন মোডে Realtime Database টেস্টিং ও HTTP ফাংশন
- অফলাইন মোডে Realtime Database ও HTTP ফাংশন টেস্টিং
আরও জানতে, firebase-functions-test-এর জন্য API রেফারেন্স
দেখুন।