Bu sayfada, işletmeniz için birim testleri yazmaya yönelik en iyi uygulamalar ve araçlar açıklanmaktadır
Sürekli Entegrasyon'un (CI) parçası olacak testler gibi işlevler
bahsedeceğim. Firebase, testi kolaylaştırmak amacıyla Cloud Functions için Firebase Test SDK sağlar. Google
npm'de firebase-functions-test
olarak dağıtılır ve tamamlayıcı test SDK'sıdır
Hedef: firebase-functions
. Cloud Functions için Firebase Test SDK:
- Uygun ayarları yapar ve testleriniz için gerekli ayarları yapar, örneğin şunları içerir:
firebase-functions
için gereken ortam değişkenlerini ayarlayıp ayarlamadan kaldırın. - Yalnızca belirtmeniz gereken örnek veriler ve etkinlik bağlamı oluşturur testinizle ilgili tüm alanları inceleyin.
Test kurulumu
Hem firebase-functions-test
hem de Mocha'yı yükleyin.
test çerçevesini kullanabilirsiniz. Bunun için işlev klasörünüzde aşağıdaki komutları çalıştırın:
npm install --save-dev firebase-functions-test
npm install --save-dev mocha
Sonra, işlevler klasöründe bir test
klasörü ve yeni bir dosya oluşturun.
kod olarak ekleyin ve index.test.js
gibi bir ad verin.
Son olarak, aşağıdakini eklemek için functions/package.json
öğesini değiştirin:
"scripts": {
"test": "mocha --reporter spec"
}
Testleri yazdıktan sonra içeride npm test
komutunu çalıştırarak test edebilirsiniz.
dizin oluşturun.
Cloud Functions için Firebase Test SDK başlatılıyor
firebase-functions-test
iki şekilde kullanılabilir:
- Online mod (önerilir): Bir Firebase projesiyle etkileşim kuran testler yazın yazma, kullanıcı oluşturma vb. işlemlerin yapılmasını sağlamak için gereken ve test kodunuz sonuçları inceleyebilir. Bu, aynı zamanda diğer İşlevlerinizde kullanılan Google SDK'ları da çalışır.
- Çevrimdışı mod: Yan etki olmadan, ayrı ayrı ve çevrimdışı birim testleri yazın. Yani, Firebase ürünüyle (ör. veya kullanıcı oluşturma gibi) stublaştırılması gerekir. Çevrimdışı kullanılıyor Cloud Firestore veya Realtime Database kullanıyorsanız mod genellikle önerilmez işlevini kullanın.
SDK'yı online modda başlat (önerilir)
Bir test projesiyle etkileşim kuran testler yazmak istiyorsanız
uygulamayı ilk kullanıma hazırlamak için gereken proje yapılandırma değerlerini sağlayın:
firebase-admin
ve bir hizmet hesabı anahtar dosyasının yolu.
Firebase projenizin yapılandırma değerlerini almak için:
- Proje ayarlarınızı şurada açın: Firebase konsolu.
- Uygulamalarınız bölümünde istediğiniz uygulamayı seçin.
Sağ bölmede, yapılandırma dosyası indirme seçeneğini belirleyin yeniden hedefleme kampanyaları için kullanılabilir.
Web uygulamaları için Yapılandırma'yı seçerek görüntüleyin yapılandırma değerleridir.
Anahtar dosyası oluşturmak için:
- Hizmet Hesapları bölmesini açın. Google Cloud konsolunda görebilirsiniz.
- Varsayılan App Engine hizmet hesabını seçin ve şuradaki seçenekler menüsünü kullanın: Anahtar oluştur'u seçmek için sağına dokunun.
- İstendiğinde anahtar türü için JSON'u seçin ve Create'i (Oluştur) tıklayın.
Anahtar dosyasını kaydettikten sonra SDK'yı başlatın:
// 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'yı çevrimdışı modda başlat
Tamamen çevrimdışı testler yazmak isterseniz SDK'yı başlatabilirsiniz hiçbir parametre olmadan:
// At the top of test/index.test.js
const test = require('firebase-functions-test')();
Sahte yapılandırma değerleri
İşlevler kodunuzda functions.config()
kullanıyorsanız yapılandırmayla deneme yapabilirsiniz.
değerler. Örneğin, functions/index.js
aşağıdaki kodu içeriyorsa:
const functions = require('firebase-functions/v1');
const key = functions.config().stripe.key;
Ardından, test dosyanızın içindeki değeri aşağıdaki şekilde oluşturabilirsiniz:
// Mock functions config values
test.mockConfig({ stripe: { key: '23wr42ewr34' }});
İşlevlerinizi içe aktarma
İşlevlerinizi içe aktarmak için require
kullanarak ana işlev dosyanızı
modülünü kullanabilirsiniz. Bunu yalnızca firebase-functions-test
,
yapılandırma değerleridir.
// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code
firebase-functions-test
uygulamasını şurada başlattıysanız:
çevrimdışı modda ve
admin.initializeApp()
kullanıyorsanız, daha önce bunu saplamanız gerekir
içe aktarma:
// 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');
Arka plan (HTTP olmayan) işlevlerini test etme
HTTP olmayan işlevleri test etme süreci aşağıdaki adımları içerir:
- Test etmek istediğiniz işlevi
test.wrap
yöntemiyle sarmalayın - Test verilerini oluşturma
- Sarmalanmış işlevi, oluşturduğunuz test verileri ve herhangi bir etkinlikle çağırma bağlam alanlarını da kullanabilirsiniz.
- Davranış hakkında iddialarda bulunmak.
Önce test etmek istediğiniz işlevi sarmalayın. Diyelim ki
makeUppercase
adlı functions/index.js
adlı katılımcının testini yapmak istiyorsunuz. Şunu yazın:
functions/test/index.test.js
içinde takip ediliyor
// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);
wrapped
, çağrıldığında makeUppercase
yöntemini çağıran bir işlevdir. wrapped
.
2 parametre alır:
- data (gerekli):
makeUppercase
ürününe gönderilecek veriler. Doğrudan bu bu parametrenin, istediğiniz fonksiyon işleyiciye gönderilen yazdı.firebase-functions-test
, özel oluşturma yöntemleri sağlar verileri veya örnek verileri içerir. - eventContextOptions (isteğe bağlı): belirtmek istediğiniz etkinlik bağlamı alanları
tercih edebilirsiniz. Etkinlik bağlamı,
fonksiyon işleyicisini kullanabilirsiniz. Bir
eventContextOptions
eklemezsenizwrapped
parametresi çağrılırken, etkinlik bağlamı oluşturulmaya devam ediyor bu verileri kullanabilirsiniz. Oluşturulan alanlardan bazılarını burada belirtmelisiniz. Yalnızca aşağıdaki gibi görünen alanları doldurmanız gerektiğini unutmayın: anahtar kelimeleri belirleyebilirsiniz. Geçersiz kılmadığınız alanlar oluşturulur.
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
});
Test verilerini oluşturma
Sarmalanmış bir işlevin ilk parametresi, koordineli olacaklardır. Test verilerini oluşturmanın birkaç yolu vardır.
Özel verileri kullanma
firebase-functions-test
, gerekli verileri oluşturmak için çeşitli işlevlere sahiptir
fonksiyonlarınızı test edin. Örneğin, test.firestore.makeDocumentSnapshot
kullanın
ve Firestore DocumentSnapshot
oluşturun. İlk bağımsız değişken veridir ve
ikinci bağımsız değişken tam referans yoludur ve
isteğe bağlı üçüncü bağımsız değişken
diğer özellikleri için de geçerli olur.
// 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
veya onWrite
işlevini test ediyorsanız
biri öncesi, diğeri sonrası durumu için olmak üzere iki anlık görüntü. Daha sonra
bu anlık görüntülerle Change
nesnesi oluşturmak için makeChange
yöntemini kullanabilir.
// 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);
Benzer işlevler için API referansına bakın diğer tüm veri türleri için geçerli.
Örnek verileri kullanma
Testlerinizde kullanılan verileri özelleştirmeniz gerekmiyorsa
firebase-functions-test
, her biri için örnek veri oluşturma yöntemleri sunar
işlev türünü belirtin.
// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();
Aşağıdaki yöntemler için API referansını inceleyin: işlev türü için örnek veriler alınıyor.
Stdubed veri kullanma (çevrimdışı mod için)
SDK'yı çevrimdışı modda başlattıysanız ve bir Cloud Firestore veya
Realtime Database işlevi için saplama içeren düz bir nesne kullanmalısınız
oluşturmak yerine gerçek bir DocumentSnapshot
veya DataSnapshot
oluşturun.
Aşağıdaki fonksiyon için bir birim testi yazdığınızı varsayalım:
// 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); });
İşlevin içinde snap
iki kez kullanılır:
snap.val()
snap.ref.parent.child('uppercase').set(uppercase)
Test kodunda, bu kod yollarının her ikisinin de çalışacağı düz bir nesne oluşturun. ve kökten değiştirmek için Sinon'u kullanın.
// 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);
Onaylama
SDK'yı başlattıktan, işlevleri sarmaladıktan ve verileri oluşturduktan sonra oluşturulan verilerle sarmalanmış işlevleri çağırabilir ve onaylamalar yapabilir düşünmesi gerekir. Şu dosyalar için Chai gibi bir kitaplık kullanabilirsiniz: en iyi uygulamaları paylaşacağım.
Online modda onaylamalar yapma
Cloud Functions için Firebase Test SDK uygulamasını çevrimiçi modda başlattıysanız:
veri tabanında yazma gibi istenilen işlemlerin (ör. veritabanına yazma)
firebase-admin
SDK'sı kullanılıyor.
Aşağıdaki örnekte 'INPUT' iddia ediliyor web sitesinin veri tabanına test projesi olabilir.
// 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'); }); });
Çevrimdışı modda onay yapma
İşlevin beklenen dönüş değeri hakkında onay alabilirsiniz:
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);
Ayrıca, Sinon casuslarını belirli yöntemlerin çağrıldığını ve beklediğiniz parametrelerle yapıldığını iddia etmek.
HTTP işlevlerini test etme
HTTP onCall işlevlerini test etmek için arka plan işlevlerini test etme ile aynı yaklaşımı kullanın.
HTTP onRequest işlevlerini test ediyorsanız
Şu koşullar geçerliyse firebase-functions-test
:
functions.config()
kullanıyorsunuz- İşleviniz bir Firebase projesiyle veya diğer Google API'leriyle etkileşime geçtiğinde ve testlerinizde gerçek bir Firebase projesini ve bu projenin kimlik bilgilerini kullanmak istiyorsunuz.
HTTP onRequest işlevi iki parametre alır: istek nesnesi ve yanıt
nesnesini tanımlayın. addMessage()
örnek işlevini nasıl test edebileceğiniz aşağıda açıklanmıştır:
sendMessage()
tarihinden itibaren yanıt nesnesindeki yönlendirme işlevini geçersiz kıl buna denir.- Yönlendirme işlevinde chai.assert parametresini kullanın. Böylece, yönlendirme işlevinin şununla çağrılmalıdır:
// 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);
Test temizliği
Test kodunuzun en sonunda temizleme işlevini çağırın. Bu politika, ayarlanmadan bırakılır
ilk kullanıma hazırlanırken SDK'nın ayarladığı ortam değişkenlerini ve
Gerçek bir SDK oluşturmak için SDK'yı kullanmanız halinde oluşturulmuş olabilecek Firebase
DataSnapshot
veya Firestore DocumentSnapshot
zaman veritabanı.
test.cleanup();
Tüm örnekleri inceleyin ve daha fazla bilgi edinin
Tüm örnekleri Firebase GitHub deposunda inceleyebilirsiniz.
- Realtime Database ve HTTP İşlevlerini Online Modda Test Etme
- Realtime Database ve HTTP İşlevlerini Çevrimdışı Modda Test Etme
Daha fazla bilgi edinmek için API referansına bakın
firebase-functions-test
için.