Na tej stronie znajdziesz sprawdzone metody i narzędzia do pisania testów jednostkowych
funkcji takich jak testy, które wchodzą w skład
ciągłej integracji (CI).
systemu. Aby ułatwić testowanie, Firebase udostępnia Firebase Test SDK dla Cloud Functions. it
jest rozpowszechniany w npm jako firebase-functions-test
i jest towarzyszącym testowym pakietem SDK
do: firebase-functions
. Firebase Test SDK dla Cloud Functions:
- Dba o odpowiednią konfigurację i sekcję testów na potrzeby testów, np.
i ustawić zmienne środowiskowe wymagane przez
firebase-functions
. - Generuje przykładowe dane i kontekst zdarzenia, więc wystarczy określić pola, które są istotne w Twoim teście.
Konfiguracja testowa
Zainstaluj zarówno firebase-functions-test
, jak i Mocha,
platformę testowania, uruchamiając w folderze funkcji te polecenia:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
Następnie utwórz folder test
w folderze funkcji, a następnie utwórz nowy plik.
wpisz w nim kod testowy i nadaj mu nazwę podobną do index.test.js
.
Na koniec zmodyfikuj functions/package.json
, by dodać te elementy:
"scripts": {
"test": "mocha --reporter spec"
}
Po napisaniu testów możesz je uruchomić, uruchamiając w nich npm test
w katalogu funkcji.
Inicjuję: Firebase Test SDK dla: Cloud Functions
Z usługi firebase-functions-test
można korzystać na 2 sposoby:
- Tryb online (zalecany): pisz testy, które współdziałają z projektem Firebase. przeznaczone do testowania, tak aby zapisy w bazie danych, tworzenie przez użytkownika itd. i można sprawdzić ich wyniki za pomocą kodu testowego. Oznacza to również, że pozostałe Będą one również działać z pakietami SDK Google używanymi w Twoich funkcjach.
- Tryb offline: możesz tworzyć silosowane i offline testy jednostkowe bez efektów ubocznych. Oznacza to, że wszystkie wywołania metod, które wchodzą w interakcję z usługą Firebase (np. do zapisu w bazie danych lub tworzenia użytkownika) należy skrócić. Korzystanie w trybie offline tryb zwykle nie jest zalecany, jeśli masz Cloud Firestore lub Realtime Database ponieważ znacznie zwiększa to złożoność kodu testowego.
Zainicjuj pakiet SDK w trybie online (zalecane)
Jeśli chcesz pisać testy współdziałające z projektem testowym, musisz:
podać wartości konfiguracji projektu wymagane do zainicjowania aplikacji
firebase-admin
oraz ścieżka do pliku klucza konta usługi.
Aby pobrać wartości konfiguracyjne projektu Firebase:
- Otwórz ustawienia projektu w Firebase.
- W sekcji Twoje aplikacje wybierz odpowiednią aplikację.
W panelu po prawej stronie wybierz opcję pobrania pliku konfiguracji dla aplikacji Apple i Androida.
W przypadku aplikacji internetowych wybierz opcję Konfiguracja, aby wyświetlić wartości konfiguracyjnych.
Aby utworzyć plik klucza:
- Otwórz panel Konta usługi. konsoli Google Cloud.
- Wybierz domyślne konto usługi App Engine i użyj menu opcji na stronie prawym przyciskiem myszy i wybierz Utwórz klucz.
- Gdy pojawi się prośba, wybierz typ klucza JSON i kliknij Utwórz.
Po zapisaniu pliku klucza zainicjuj pakiet 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');
Zainicjuj pakiet SDK w trybie offline
Jeśli chcesz pisać testy offline, możesz zainicjować pakiet SDK bez żadnych parametrów:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
Pozorowanie wartości konfiguracji
Jeśli używasz functions.config()
w kodzie funkcji, możesz symulować konfigurację
. Jeśli na przykład functions/index.js
zawiera ten kod:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
Następnie możesz symulować wartość w pliku testowym w ten sposób:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
Importowanie funkcji
Aby zaimportować funkcje, użyj narzędzia require
, aby zaimportować główny plik funkcji jako plik
. Pamiętaj, aby robić to dopiero po zainicjowaniu usługi firebase-functions-test
,
i naśladowania wartości konfiguracji.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
Jeśli zainicjowano firebase-functions-test
w
trybie offline oraz
admin.initializeApp()
w kodzie funkcji, musisz go użyć przed
importowanie funkcji:
// 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');
Testowanie funkcji w tle (innych niż HTTP)
Proces testowania funkcji innych niż HTTP obejmuje te kroki:
- Zapakuj funkcję, którą chcesz przetestować za pomocą metody
test.wrap
- Tworzenie danych testowych
- Wywołaj funkcję opakowaną z użyciem utworzonych przez Ciebie danych testowych i dowolnego zdarzenia pola kontekstu, które chcesz określić.
- Wyrażaj sobie spostrzeżenia na temat zachowań.
Najpierw zapakuj funkcję, którą chcesz przetestować. Załóżmy, że masz funkcję w
functions/index.js
o nazwie makeUppercase
, którą chcesz przetestować. Wpisz
obserwowane w grupie functions/test/index.test.js
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
to funkcja, która wywołuje funkcję makeUppercase
po jej wywołaniu. wrapped
przyjmuje 2 parametry:
- data (wymagane): dane do wysłania do usługi
makeUppercase
. To bezpośrednio odpowiada pierwszemu parametrowi wysłanemu do modułu obsługi funkcji, który co napisał.firebase-functions-test
udostępnia metody tworzenia niestandardowych lub przykładowe dane. - eventContextOptions (opcjonalnie): pola kontekstu zdarzenia, do których
określić. Kontekst zdarzenia to drugi parametr wysyłany do funkcji
modułu obsługi funkcji. Jeśli nie podasz atrybutu
eventContextOptions
podczas wywoływania funkcjiwrapped
kontekst zdarzenia jest generowany z odpowiednimi polami. Niektóre wygenerowane pola możesz zastąpić, i je określić. Pamiętaj, że musisz uwzględnić tylko te pola, które które chcesz zastąpić. Wszystkie pola, których nie zastąpiono, zostaną wygenerowane.
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
});
Tworzenie danych testowych
Pierwszym parametrem funkcji opakowanej są dane testowe do wywołania bazowego z funkcją. Dane testowe można tworzyć na kilka sposobów.
Korzystanie z danych niestandardowych
firebase-functions-test
udostępnia szereg funkcji do tworzenia danych potrzebnych
aby przetestować funkcje. Przykład: test.firestore.makeDocumentSnapshot
aby utworzyć DocumentSnapshot
Firestore. Pierwszy argument to dane, a argument
drugi argument to pełna ścieżka odniesienia i jest
opcjonalny trzeci argument
.
// 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);
Jeśli testujesz funkcję onUpdate
lub onWrite
, musisz utworzyć
ze stanem „przed” i „po” ze stanem „po”. Następnie
może użyć metody makeChange
, aby utworzyć obiekt Change
z tymi zrzutami.
// 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);
zapoznaj się z dokumentacją interfejsu API, aby uzyskać informacje o podobnych funkcjach. dla pozostałych typów danych.
Korzystanie z przykładowych danych
Jeśli nie musisz dostosowywać danych używanych podczas testów:
firebase-functions-test
oferuje metody generowania przykładowych danych dla poszczególnych
typ funkcji.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
w dokumentacji interfejsu API znajdziesz metody pobierz przykładowe dane dla każdego typu funkcji.
Używanie skróconych danych (w trybie offline)
Jeśli pakiet SDK został zainicjowany w trybie offline i testujesz pakiet Cloud Firestore lub
Realtime Database, użyj zwykłego obiektu z krotkami
zamiast tworzenia rzeczywistego DocumentSnapshot
lub DataSnapshot
.
Załóżmy, że piszesz test jednostkowy dla następującej funkcji:
// 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); });
W obrębie funkcji pole snap
jest używane dwukrotnie:
snap.val()
snap.ref.parent.child('uppercase').set(uppercase)
Utwórz w kodzie testowym zwykły obiekt, w którym będą działać obie te ścieżki kodu. i użyj polecenia Sinon, aby utworzyć atrapę metod.
// 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);
Składanie asercji
Po zainicjowaniu pakietu SDK, opakowaniu funkcji i stworzeniu danych może wywoływać opakowane funkcje z utworzonymi danymi i wykonywać asercje na temat zachowania użytkowników. Na przykład biblioteki Chai możesz używać do ustanowienie tych założeń.
Tworzenie asercji w trybie online
Jeśli Firebase Test SDK dla aplikacji Cloud Functions zostało zainicjowane w trybie online,
może określić, że pożądane działania (np. zapis w bazie danych) zostały wykonane przez
za pomocą pakietu SDK firebase-admin
.
W poniższym przykładzie potwierdza się, że „INPUT” została zapisana w bazie danych projektu testowego.
// 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'); }); });
Tworzenie asercji w trybie offline
Możesz składać asercje dotyczące oczekiwanej wartości zwracanej przez funkcję:
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);
Możesz też użyć szpiegów Sinona, aby: zapewnić, że zostały wywołane określone metody z oczekiwanymi parametrami.
Testowanie funkcji HTTP
Aby przetestować funkcje HTTP onCall, użyj tej samej metody co do testowania funkcji w tle.
Jeśli testujesz funkcje HTTP onRequest, użyj
firebase-functions-test
, jeśli:
- Używasz
functions.config()
- Twoja funkcja współdziała z projektem Firebase lub innymi interfejsami API Google, chcesz używać w testach prawdziwego projektu Firebase i jego danych logowania.
Funkcja HTTP onRequest ma 2 parametry: obiekt żądania i odpowiedź
obiektu. Oto jak możesz przetestować przykładową funkcję addMessage()
:
- Zastąp funkcję przekierowania w obiekcie odpowiedzi, ponieważ
sendMessage()
właśnie na to. - W ramach funkcji przekierowania użyj polecenia chai.assert. aby ułatwić sobie określenie, jakie parametry powinna wykonywać funkcja przekierowująca być wywołana przy użyciu:
// 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);
Czyszczenie testowe
Na samym końcu kodu testowego wywołaj funkcję czyszczenia. Wyłącza to ustawienie
zmiennych środowiskowych ustawionych przez pakiet SDK podczas inicjowania,
aplikacje Firebase, które mogły zostać utworzone, jeśli użyto pakietu SDK do utworzenia prawdziwego
DataSnapshot
lub Firestore DocumentSnapshot
.
test.cleanup();
Zapoznaj się z pełnymi przykładami i dowiedz się więcej
Pełne przykłady znajdziesz w repozytorium Firebase na GitHubie.
- Testowanie funkcji Realtime Database i HTTP w trybie online
- Testowanie funkcji Realtime Database i HTTP w trybie offline
Więcej informacji znajdziesz w dokumentacji interfejsu API.
za firebase-functions-test
.