Unit testing of Cloud Functions

This page describes best practices and tools for writing unit tests for yourfunctions, such as tests that would be a part of a Continuous Integration (CI)system. To make testing easier, Firebase provides theFirebase Test SDK forCloud Functions. Itis distributed on npm asfirebase-functions-test, and is a companion test SDKtofirebase-functions. TheFirebase Test SDK forCloud Functions:

  • Takes care of the appropriate setup and teardown for your tests, such assetting and unsetting environment variables needed byfirebase-functions.
  • Generates sample data and event context, so that you only have to specifythe fields that are relevant to your test.
Note:firebase-functions-test can only be used with functions written withfirebase-functions 2.0.0 or above.

Test setup

Install bothfirebase-functions-test andMocha, atesting framework, by running the following commands in your functions folder:

npm install --save-dev firebase-functions-testnpm install --save-dev mocha

Next create atest folder inside the functions folder, create a new fileinside it for your test code, and name it something likeindex.test.js.

Finally, modifyfunctions/package.json to add the following:

"scripts": {  "test": "mocha --reporter spec"}

Once you have written the tests, you can run them by runningnpm test insideyour functions directory.

InitializingFirebase Test SDK forCloud Functions

There are two ways to usefirebase-functions-test:

  1. Online mode (recommended): Write tests that interact with a Firebase projectdedicated to testing so that database writes, user creates, etc. would actuallyhappen, and your test code can inspect the results. This also means that otherGoogle SDKs used in your functions will work as well.
  2. Offline mode: Write siloed and offline unit tests with no side effects.This means that any method calls that interact with a Firebase product (e.g.writing to the database or creating a user) need to be stubbed. Using offlinemode is generally not recommended if you haveCloud Firestore orRealtime Databasefunctions, since it greatly increases the complexity of your test code.

Initialize SDK in online mode (recommended)

If you would like to write tests that interact with a test project, you need tosupply the project config values that are needed for initializing the app throughfirebase-admin, and the path to a service account key file.

To get your Firebase project's config values:

  1. Open your project settings in theFirebase console.
  2. InYour apps, select the desired app.
  3. In the right pane, select the option to download a configuration filefor Apple and Android apps.

    For web apps, selectConfig to displayconfiguration values.

To create a key file:

  1. Open theService Accounts paneof theGoogle Cloud console.
  2. Select theApp Engine default service account, and use the options menu atthe right to selectCreate key.
  3. When prompted, select JSON for the key type, and clickCreate.

After saving the key file, initialize the SDK:

//Atthetopoftest/index.test.js//MakesuretousevaluesfromyouractualFirebaseconfigurationconsttest=require('firebase-functions-test')({databaseURL:'https://PROJECT_ID.firebaseio.com',storageBucket:'PROJECT_ID.firebasestorage.app',projectId:'PROJECT_ID',},'path/to/serviceAccountKey.json');
Warning: Use extra caution when handling service account credentials in your code. Do not commit them to a public repository, deploy them in a client app, or expose them in any way that could compromise the security of your Firebase project.

Initialize SDK in offline mode

If you would like to write completely offline tests, you can initialize the SDKwithout any parameters:

//Atthetopoftest/index.test.jsconsttest=require('firebase-functions-test')();

Mocking config values

If you usefunctions.config() in your functions code, you can mock the configvalues. For example, iffunctions/index.js contains the following code:

constfunctions=require('firebase-functions/v1');constkey=functions.config().stripe.key;

Then you can mock the value inside your test file like so:

// Mock functions config valuestest.mockConfig({stripe:{key:'23wr42ewr34'}});

Importing your functions

To import your functions, userequire to import your main functions file as amodule.Be sure to only do this after initializingfirebase-functions-test,and mocking config values.

//afterfirebase-functions-testhasbeeninitializedconstmyFunctions=require('../index.js');//relativepathtofunctionscode

If you initializedfirebase-functions-test inoffline mode, and you haveadmin.initializeApp() in your functions code, then you need to stub it beforeimporting your functions:

//Ifindex.jscallsadmin.initializeAppatthetopofthefile,//weneedtostubitoutbeforerequiringindex.js.Thisisbecausethe//functionswillbeexecutedasapartoftherequireprocess.//Herewestubadmin.initializeApptobeadummyfunctionthatdoesn't do anything.adminInitStub=sinon.stub(admin,'initializeApp');//Nowwecanrequireindex.jsandsavetheexportsinsideanamespacecalledmyFunctions.myFunctions=require('../index');

Testing background (non-HTTP) functions

The process for testing non-HTTP functions involves the following steps:

  1. Wrap the function you would like to test with thetest.wrap method
  2. Construct test data
  3. Invoke the wrapped function with the test data you constructed and any eventcontext fields you'd like to specify.
  4. Make assertions about behavior.

First wrap the function you'd like to test. Let's say you have a function infunctions/index.js calledmakeUppercase, which you'd like to test. Write thefollowing infunctions/test/index.test.js

//"Wrap"themakeUpperCasefunctionfromindex.jsconstmyFunctions=require('../index.js');constwrapped=test.wrap(myFunctions.makeUppercase);

wrapped is a function which invokesmakeUppercase when it is called.wrappedtakes 2 parameters:

  1. data (required): the data to send tomakeUppercase. This directlycorresponds to the first parameter sent to the function handler that youwrote.firebase-functions-test provides methods for constructing customdata or example data.
  2. eventContextOptions (optional): fields of the event context that you'dlike to specify. The event context is the second parameter sent to thefunction handler that you wrote. If you do not include aneventContextOptionsparameter when callingwrapped, an event context is still generatedwith sensible fields. You can override some of the generated fields byspecifying them here. Note that you only have to include the fields thatyou'd like to override. Any fields that you did not override are generated.
constdata=//Seenextsectionforconstructingtestdata//Invokethewrappedfunctionwithoutspecifyingtheeventcontext.wrapped(data);//Invokethefunction,andspecifyparamswrapped(data,{params:{pushId:'234234'}});//Invokethefunction,andspecifyauthandauthType(forrealtimedatabasefunctionsonly)wrapped(data,{auth:{uid:'jckS2Q0'},authType:'USER'});//Invokethefunction,andspecifyallthefieldsthatcanbespecifiedwrapped(data,{eventId:'abc',timestamp:'2018-03-23T17:27:17.099Z',params:{pushId:'234234'},auth:{uid:'jckS2Q0'//onlyforrealtimedatabasefunctions},authType:'USER'//onlyforrealtimedatabasefunctions});

Constructing test data

The first parameter of a wrapped function is the test data to invoke the underlyingfunction with. There are a number of ways to construct test data.

Using custom data

firebase-functions-test has a number of functions for constructing data neededto test your functions. For example, usetest.firestore.makeDocumentSnapshotto create a FirestoreDocumentSnapshot. The first argument is the data, and thesecond argument is the full reference path, and there is anoptional third argumentfor other properties of the snapshot you can specify.

//Makesnapshotconstsnap=test.firestore.makeDocumentSnapshot({foo:'bar'},'document/path');//Callwrappedfunctionwiththesnapshotconstwrapped=test.wrap(myFunctions.myFirestoreDeleteFunction);wrapped(snap);

If you are testing anonUpdate oronWrite function, you'll need to createtwo snapshots: one for the before state and one for the after state. Then, youcan use themakeChange method to create aChange object with these snapshots.

//MakesnapshotforstateofdatabasebeforehandconstbeforeSnap=test.firestore.makeDocumentSnapshot({foo:'bar'},'document/path');//MakesnapshotforstateofdatabaseafterthechangeconstafterSnap=test.firestore.makeDocumentSnapshot({foo:'faz'},'document/path');constchange=test.makeChange(beforeSnap,afterSnap);//CallwrappedfunctionwiththeChangeobjectconstwrapped=test.wrap(myFunctions.myFirestoreUpdateFunction);wrapped(change);
Note: You should only construct custom data forCloud Firestore andRealtime Databaseif you initialized the SDK inonline mode. Otherwise,you should usestubbed data to avoid unexpected behavior.

See theAPI reference for similar functionsfor all the other data types.

Using example data

If you don't need to customize the data used in the your tests, thenfirebase-functions-test offers methods for generating example data for eachfunction type.

//ForFirestoreonCreateoronDeletefunctionsconstsnap=test.firestore.exampleDocumentSnapshot();//ForFirestoreonUpdateoronWritefunctionsconstchange=test.firestore.exampleDocumentSnapshotChange();
Note: You should only construct example data forCloud Firestore andRealtime Databaseif you initialized the SDK inonline mode. Otherwise,you should usestubbed data to avoid unexpected behavior.

See theAPI reference for methods forgetting example data for every function type.

Using stubbed data (for offline mode)

If you initialized the SDK in offline mode, and are testing aCloud Firestore orRealtime Database function, you should use a plain object with stubsinstead of creating an actualDocumentSnapshot orDataSnapshot.

Let's say you are writing a unit test for the following function:

//Listensfornewmessagesaddedto/messages/:pushId/originalandcreatesan//uppercaseversionofthemessageto/messages/:pushId/uppercaseexports.makeUppercase=functions.database.ref('/messages/{pushId}/original').onCreate((snapshot,context)=>{//GrabthecurrentvalueofwhatwaswrittentotheRealtimeDatabase.constoriginal=snapshot.val();functions.logger.log('Uppercasing',context.params.pushId,original);constuppercase=original.toUpperCase();//YoumustreturnaPromisewhenperformingasynchronoustasksinsideaFunctionssuchas//writingtotheFirebaseRealtimeDatabase.//Settingan"uppercase"siblingintheRealtimeDatabasereturnsaPromise.returnsnapshot.ref.parent.child('uppercase').set(uppercase);});

Inside of the function,snap is used twice:

  • snap.val()
  • snap.ref.parent.child('uppercase').set(uppercase)

In test code, create a plain object where both of these code paths will work,and useSinon to stub the methods.

//Thefollowinglinescreatesafakesnapshot,'snap',whichreturns'input'whensnap.val()iscalled,//andreturnstruewhensnap.ref.parent.child('uppercase').set('INPUT')iscalled.constsnap={val:()=>'input',ref:{parent:{child:childStub,}}};childStub.withArgs(childParam).returns({set:setStub});setStub.withArgs(setParam).returns(true);

Making assertions

After initializing the SDK, wrapping the functions, and constructing data, youcan invoke the wrapped functions with the constructed data and make assertionsabout behavior. You can use a library such asChai formaking these assertions.

Making assertions in online mode

If you initialized theFirebase Test SDK forCloud Functions inonline mode, youcan assert that the desired actions (such as a database write) has taken place byusing thefirebase-admin SDK.

The example below asserts that 'INPUT' has been written into the database of thetest project.

//CreateaDataSnapshotwiththevalue'input'andthereferencepath'messages/11111/original'.constsnap=test.database.makeDataSnapshot('input','messages/11111/original');//WrapthemakeUppercasefunctionconstwrapped=test.wrap(myFunctions.makeUppercase);//Callthewrappedfunctionwiththesnapshotyouconstructed.returnwrapped(snap).then(()=>{//Readthevalueofthedataatmessages/11111/uppercase.Because`admin.initializeApp()`is//calledinfunctions/index.js,there's already a Firebase app initialized. Otherwise, add//`admin.initializeApp()`beforethisline.returnadmin.database().ref('messages/11111/uppercase').once('value').then((createdSnap)=>{//Assertthatthevalueistheuppercasedversionofourinput.assert.equal(createdSnap.val(),'INPUT');});});

Making assertions in offline mode

You can make assertions about the expected return value of the function:

constchildParam='uppercase';constsetParam='INPUT';//Stubsareobjectsthatfakeand/orrecordfunctioncalls.//Theseareexcellentforverifyingthatfunctionshavebeencalledandtovalidatethe//parameterspassedtothosefunctions.constchildStub=sinon.stub();constsetStub=sinon.stub();//Thefollowinglinescreatesafakesnapshot,'snap',whichreturns'input'whensnap.val()iscalled,//andreturnstruewhensnap.ref.parent.child('uppercase').set('INPUT')iscalled.constsnap={val:()=>'input',ref:{parent:{child:childStub,}}};childStub.withArgs(childParam).returns({set:setStub});setStub.withArgs(setParam).returns(true);//WrapthemakeUppercasefunction.constwrapped=test.wrap(myFunctions.makeUppercase);//Sincewe've stubbed snap.ref.parent.child(childParam).set(setParam) to return true if it was//calledwiththeparametersweexpect,weassertthatitindeedreturnedtrue.returnwrapped(snap).then(makeUppercaseResult=>{returnassert.equal(makeUppercaseResult,true);});

You can also usedSinon spies toassert that certain methods have been called, and with parameters you expect.

Testing HTTP functions

To test HTTP onCall functions, use the same approach astesting background functions.

If you are testing HTTP onRequest functions, you should usefirebase-functions-test if:

  • You usefunctions.config()
  • Your function interacts with a Firebase project or other Google APIs, andyou'd like to use a real Firebase project and its credentials for your tests.

An HTTP onRequest function takes two parameters: a request object and a responseobject. Here is how you might test theaddMessage() example function:

  • Override the redirect function in the response object, sincesendMessage()calls it.
  • Within the redirect function, usechai.assertto help make assertions about what parameters the redirect function shouldbe called with:
//Afakerequestobject,withreq.query.textsetto'input'constreq={query:{text:'input'}};//Afakeresponseobject,withastubbedredirectfunctionwhichassertsthatitiscalled//withparameters303,'new_ref'.constres={redirect:(code,url)=>{assert.equal(code,303);assert.equal(url,'new_ref');done();}};//InvokeaddMessagewithourfakerequestandresponseobjects.Thiswillcausethe//assertionsintheresponseobjecttobeevaluated.myFunctions.addMessage(req,res);

Test cleanup

At the very end of your test code, call the cleanup function. This unsetsenvironment variables that the SDK set when it was initialized, and deletesFirebase apps that may have been created if you used the SDK to create a realtime databaseDataSnapshot or FirestoreDocumentSnapshot.

test.cleanup();

Review complete examples and learn more

You can review the complete examples on the Firebase GitHub repository.

To learn more, refer to theAPI referenceforfirebase-functions-test.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2026-02-18 UTC.