इस पेज पर, फ़ंक्शन के लिए यूनिट टेस्ट लिखने के सबसे सही तरीके और टूल के बारे में बताया गया है. जैसे, ऐसे टेस्ट जो लगातार इंटिग्रेशन (सीआई) सिस्टम का हिस्सा होंगे. जांच को आसान बनाने के लिए, Firebase Cloud Functions के लिए Firebase Test SDK उपलब्ध कराता है. इसे npm पर firebase-functions-test के तौर पर उपलब्ध कराया जाता है. यह firebase-functions के लिए, टेस्ट करने वाला एक कंपैनियन SDK टूल है. Cloud Functions के लिए Firebase Test SDK:
- यह आपके टेस्ट के लिए सही सेटअप और टियरडाउन का ध्यान रखता है. जैसे,
firebase-functionsके लिए ज़रूरी एनवायरमेंट वैरिएबल सेट करना और अनसेट करना. - यह सैंपल डेटा और इवेंट कॉन्टेक्स्ट जनरेट करता है, ताकि आपको सिर्फ़ उन फ़ील्ड की जानकारी देनी पड़े जो आपके टेस्ट के लिए ज़रूरी हैं.
टेस्ट सेटअप
अपने फ़ंक्शन फ़ोल्डर में ये कमांड चलाकर, firebase-functions-test और Jest, दोनों को इंस्टॉल करें. Jest एक टेस्टिंग फ़्रेमवर्क है:
npm install --save-dev firebase-functions-test
npm install --save-dev jest
इसके बाद, फ़ंक्शन फ़ोल्डर में 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 फ़ंक्शन हैं, तो आम तौर पर ऑफ़लाइन मोड का इस्तेमाल करने का सुझाव नहीं दिया जाता. ऐसा इसलिए, क्योंकि इससे आपके टेस्ट कोड की जटिलता काफ़ी बढ़ जाती है.
एसडीके को ऑनलाइन मोड में शुरू करना (सुझाया गया)
अगर आपको टेस्ट प्रोजेक्ट के साथ इंटरैक्ट करने वाले टेस्ट लिखने हैं, तो आपको Firebase कॉन्फ़िगरेशन की वे वैल्यू देनी होंगी जो firebase-admin के ज़रिए ऐप्लिकेशन को शुरू करने के लिए ज़रूरी हैं. साथ ही, आपको सेवा खाते की कुंजी वाली फ़ाइल का पाथ भी देना होगा.
Firebase कॉन्फ़िगरेशन की वैल्यू पाने के लिए:
Firebase कंसोल में,
सेटिंग > सामान्य पेज पर जाएं.स्क्रोल करके आपके ऐप्लिकेशन कार्ड पर जाएं और वह ऐप्लिकेशन चुनें जिसे आपको अनइंस्टॉल करना है.
Firebase कॉन्फ़िगरेशन पाने के लिए:
Apple और Android ऐप्लिकेशन के लिए, कॉन्फ़िगरेशन फ़ाइल डाउनलोड करने का विकल्प चुनें.
वेब ऐप्लिकेशन के लिए, कॉन्फ़िगरेशन वैल्यू देखने के लिए कॉन्फ़िगरेशन को चुनें.
कुंजी फ़ाइल बनाने के लिए:
Google Cloud कंसोल में, सेवा खाते पैनल पर जाएं.
App Engine डिफ़ॉल्ट सेवा खाता चुनें. इसके बाद, दाईं ओर मौजूद विकल्प मेन्यू का इस्तेमाल करके, कुंजी बनाएं को चुनें.
जब आपसे कुंजी का टाइप चुनने के लिए कहा जाए, तब JSON चुनें और Create पर क्लिक करें.
कुंजी वाली फ़ाइल सेव करने के बाद, 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 टूल को शुरू किया जा सकता है:
// 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 को 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');
बैकग्राउंड (नॉन-एचटीटीपी) फ़ंक्शन की जांच करना
नॉन-एचटीटीपी फ़ंक्शन की जांच करने के लिए, यह तरीका अपनाएं:
- जिस फ़ंक्शन की जांच करनी है उसे
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 में कई फ़ंक्शन हैं. इनकी मदद से, फ़ंक्शन की जांच करने के लिए ज़रूरी डेटा बनाया जा सकता है. उदाहरण के लिए, Firestore DocumentSnapshot बनाने के लिए test.firestore.makeDocumentSnapshot का इस्तेमाल करें. पहला आर्ग्युमेंट डेटा है और दूसरा आर्ग्युमेंट पूरा रेफ़रंस पाथ है. इसके अलावा, स्नैपशॉट की अन्य प्रॉपर्टी के लिए, तीसरा आर्ग्युमेंट भी दिया जा सकता है.
// 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);
अन्य सभी डेटा टाइप के लिए, मिलते-जुलते फ़ंक्शन के बारे में जानने के लिए, एपीआई का रेफ़रंस देखें.
उदाहरण के तौर पर दिए गए डेटा का इस्तेमाल करना
अगर आपको अपने टेस्ट में इस्तेमाल किए गए डेटा को पसंद के मुताबिक बनाने की ज़रूरत नहीं है, तो 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();
हर फ़ंक्शन टाइप के लिए उदाहरण के तौर पर डेटा पाने के तरीकों के बारे में जानने के लिए, एपीआई का संदर्भ देखें.
स्टब किए गए डेटा का इस्तेमाल करना (ऑफ़लाइन मोड के लिए)
अगर आपने एसडीके को ऑफ़लाइन मोड में शुरू किया है और 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, } } };
दावे करना
एसडीके टूल को शुरू करने, फ़ंक्शन को रैप करने, और डेटा बनाने के बाद, बनाए गए डेटा के साथ रैप किए गए फ़ंक्शन को शुरू किया जा सकता है. साथ ही, व्यवहार के बारे में दावे किए जा सकते हैं. इन दावों को करने के लिए, 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 मॉक फ़ंक्शन का इस्तेमाल करके, यह दावा भी किया जा सकता है कि कुछ खास तरीकों को कॉल किया गया है. साथ ही, उन पैरामीटर के साथ कॉल किया गया है जिनकी आपको उम्मीद है.
एचटीटीपी फ़ंक्शन की जांच करना
एचटीटीपी onCall फ़ंक्शन की जांच करने के लिए, वही तरीका अपनाएं जो बैकग्राउंड फ़ंक्शन की जांच करने के लिए अपनाया जाता है.
अगर आपको एचटीटीपी onRequest फ़ंक्शन की जांच करनी है, तो आपको firebase-functions-test का इस्तेमाल करना चाहिए, अगर:
functions.config()का इस्तेमाल किया जा रहा है- आपका फ़ंक्शन, किसी Firebase प्रोजेक्ट या अन्य Google API के साथ इंटरैक्ट करता है. साथ ही, आपको अपने टेस्ट के लिए, किसी असली Firebase प्रोजेक्ट और उसके क्रेडेंशियल का इस्तेमाल करना है.
एचटीटीपी onRequest फ़ंक्शन में दो पैरामीटर होते हैं: एक अनुरोध ऑब्जेक्ट और एक जवाब ऑब्जेक्ट. यहां addMessage() उदाहरण फ़ंक्शन को टेस्ट करने का तरीका बताया गया है:
स्टब
admin.database(), क्योंकिaddMessage()रीयलटाइम डेटाबेस में पुश करता है. ऑफ़लाइन मोड में, आपने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 टूल ने शुरू होने पर सेट किया था. साथ ही, यह उन Firebase ऐप्लिकेशन को मिटा देता है जो SDK टूल का इस्तेमाल करके रीयल टाइम डेटाबेस DataSnapshot या Firestore DocumentSnapshot बनाने पर बने होंगे.
test.cleanup();
पूरी तरह से तैयार उदाहरण देखें और ज़्यादा जानें
Firebase GitHub रिपॉज़िटरी पर जाकर, पूरे उदाहरण देखे जा सकते हैं.
- ऑनलाइन मोड में Realtime Database और एचटीटीपी फ़ंक्शन की जांच करना
- ऑफ़लाइन मोड में Realtime Database और एचटीटीपी फ़ंक्शन की जांच करना
ज़्यादा जानने के लिए, firebase-functions-test के लिए एपीआई का रेफ़रंस देखें.