Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

Bulut İşlevlerinin birim testi

Bu sayfa, Sürekli Entegrasyon (CI) sisteminin bir parçası olacak testler gibi, işlevleriniz için birim testleri yazmaya yönelik en iyi uygulamaları ve araçları açıklar. Firebase, testi kolaylaştırmak için Cloud Functions için Firebase Test SDK'sını sağlar. Sanki NPM üzerinde dağıtılır firebase-functions-test ve bir refakatçi testi SDK firebase-functions . Bulut İşlevleri için Firebase Test SDK'sı:

  • Böyle ihtiyaç duyduğu ayarı ve unsetting ortam değişkenleri olarak testler, uygun kurulum bakım ve söküm Alır firebase-functions .
  • Örnek veriler ve olay bağlamı oluşturur, böylece yalnızca testinizle ilgili alanları belirtmeniz gerekir.

Test kurulumu

Her iki yükleme firebase-functions-test ve Mocha klasör fonksiyonları aşağıdaki komutları çalıştırarak, bir test çerçevesi,:

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

Sonraki bir oluşturmak test , fonksiyonlar klasörünün içindeki klasörü test kodu için içine yeni bir dosya oluşturun ve bu gibi bir isim index.test.js .

Son olarak, modifiye functions/package.json aşağıdakileri ekleyin:

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

Eğer testler yazılı sonra, çalıştırarak bunları çalıştırabilirsiniz npm test sizin fonksiyonları dizini içine.

Cloud Functions için Firebase Test SDK'sını Başlatma

Kullanmanın iki yolu vardır firebase-functions-test :

  1. Online modu (önerilir): Bir Firebase projesi ile etkileşim o veritabanı yazıyor, kullanıcı oluşturur, böylece test için ayrılmış olduğunu Yaz testler, vs. aslında olur ve test kodu sonuçlarını kontrol edilebilmektedir. Bu aynı zamanda işlevlerinizde kullanılan diğer Google SDK'larının da çalışacağı anlamına gelir.
  2. Çevrimdışı modu: Yaz silolaştırılmış ve hiçbir yan etkisi ile çevrimdışı birim testleri. Bu, bir Firebase ürünüyle etkileşime giren herhangi bir yöntem çağrılarının (örneğin, veritabanına yazma veya bir kullanıcı oluşturma) saplanması gerektiği anlamına gelir. Test kodunuzun karmaşıklığını büyük ölçüde artırdığından, Cloud Firestore veya Realtime Database işlevlerine sahipseniz çevrimdışı modun kullanılması genellikle önerilmez.

SDK'yı çevrimiçi modda başlat (önerilir)

Yazma testlerine istiyorsanız bir test projesi ile etkileşim, çıkan sonuçlara uygulamayı başlatma için gerekli olan proje yapılandırma değerlerini sağlamak için gerekmez firebase-admin ve bir hizmet hesabı anahtarı dosyasının yolunu belirtir.

Firebase projenizin yapılandırma değerlerini almak için:

  1. Daki proje ayarlarını açın Firebase konsoluna .
  2. Kişisel uygulamalarda, istenen uygulamayı seçin.
  3. Sağ bölmede, iOS ve Android uygulamaları için bir yapılandırma dosyası indirme seçeneğini belirleyin.

    Web uygulamaları için yapılandırma değerlerini görüntülemek için Config'i seçin.

Bir anahtar dosyası oluşturmak için:

  1. Hizmet Hesapları bölmesini Google Bulut Konsolu.
  2. App Engine varsayılan hizmet hesabı seçin ve anahtar oluşturun seçmek için sağda seçenekler menüsünü kullanın.
  3. İstendiğinde, anahtar türü için JSON seçin ve Oluştur'u 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 istiyorsanız, SDK'yı herhangi bir parametre olmadan başlatabilirsiniz:

// At the top of test/index.test.js
const test = require('firebase-functions-test')();

alaycı yapılandırma değerleri

Eğer kullanırsanız functions.config() sizin fonksiyonları kodunda, sen yapılandırma değerlerini alay edebilir. Örneğin, eğer functions/index.js şu kodu içerir:

const functions = require('firebase-functions');
const key = functions.config().stripe.key;

Ardından, test dosyanızın içindeki değeri şu şekilde taklit edebilirsiniz:

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

İşlevlerinizi içe aktarma

Fonksiyonlarınızı aktarmak için, kullanım require bir modül olarak ana fonksiyonları dosyasını almak için. Yaptığınızdan emin olun sadece başlatılıyor sonra bunu firebase-functions-test ve yapılandırma değerlerini alay.

// after firebase-functions-test has been initialized
const myFunctions = require('../index.js'); // relative path to functions code

Eğer başlatıldı ise firebase-functions-test de çevrimdışı mod ve sahip admin.initializeApp() sizin fonksiyonları kodunda, o zaman işlevlerini ithal önce saplama gerekir:

// 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:

  1. Fonksiyonunu sarın Birlikte test etmek istiyorum test.wrap yöntemiyle
  2. Test verilerini oluştur
  3. Oluşturduğunuz test verileriyle ve belirtmek istediğiniz olay bağlamı alanlarıyla sarmalanmış işlevi çağırın.
  4. Davranış hakkında iddialarda bulunun.

Önce test etmek istediğiniz işlevi sarın. Let Diyelim ki bir işlev olduğunu varsayalım functions/index.js denilen makeUppercase Eğer teste istiyorum. İçinde aşağıdakileri yazın functions/test/index.test.js

// "Wrap" the makeUpperCase function from index.js
const myFunctions = require('../index.js');
const wrapped = test.wrap(myFunctions.makeUppercase);

wrapped çağıran bir fonksiyonudur makeUppercase çağrıldığında. wrapped 2 parametreleri alır:

  1. veri (gerekli): Veriler göndermek için makeUppercase . Bu, doğrudan yazdığınız işlev işleyicisine gönderilen ilk parametreye karşılık gelir. firebase-functions-test özel veri veya örneğin veri oluşturmak için yöntemler sağlar.
  2. eventContextOptions (opsiyonel): Olay bağlamda alanları belirtmek istediğinizi. Olay bağlamı, yazdığınız işlev işleyicisine gönderilen ikinci parametredir. Bir dahil etmezseniz eventContextOptions çağrılırken parametre wrapped , bir olay bağlam hala mantıklı alanları ile oluşturulur. Oluşturulan alanların bazılarını burada belirterek geçersiz kılabilirsiniz. Yalnızca geçersiz kılmak istediğiniz alanları eklemeniz gerektiğini unutmayın. Geçersiz kılmadığınız tüm 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 verilerinin oluşturulması

Sarılmış bir işlevin ilk parametresi, temel işlevi çağırmak için test verileridir. Test verilerini oluşturmanın birkaç yolu vardır.

Özel verileri kullanma

firebase-functions-test sizin fonksiyonlarını test için gerekli verileri oluşturmak için fonksiyonları bir numarası vardır. Örneğin, kullanmak test.firestore.makeDocumentSnapshot bir Firestore oluşturmak için DocumentSnapshot . İlk argüman veridir ve ikinci argüman tam referans yoludur ve bir orada bağlı üçüncü argüman Belirtebileceğiniz anlık diğer özellikleri için.

// 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);

Bir test ediyorsanız onUpdate veya onWrite fonksiyonu, iki anlık oluşturmak gerekir: sonra devlet için önce devlet için diğeri. Ardından, kullanabilirsiniz makeChange bir oluşturmak için yöntem Change bu enstantane ile nesneyi.

// 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);

Bkz API başvurusuna tüm diğer veri türleri için benzer fonksiyonlar için.

Örnek verileri kullanma

Eğer testlerde kullanılan verileri, daha sonra özelleştirmek gerekmiyorsa firebase-functions-test her fonksiyon tipi için örnek verileri oluşturmak için teklifler yöntemleri.

// For Firestore onCreate or onDelete functions
const snap = test.firestore.exampleDocumentSnapshot();
// For Firestore onUpdate or onWrite functions
const change = test.firestore.exampleDocumentSnapshotChange();

Bkz API başvurusu , her işlev türü örneğin veri almak için yöntemler.

Stubbed verileri kullanma (çevrimdışı mod için)

Çevrimdışı modda SDK başlatıldı ve Bulut Firestore veya Gerçek Zamanlı Veri Tabanı fonksiyonunu test ediyorsanız, bunun yerine gerçek bir yaratma taslakları ile düz bir nesne kullanmalıdır DocumentSnapshot veya DataSnapshot .

Aşağıdaki işlev 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);
    });

Fonksiyonun içinde, snap iki kez kullanılır:

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

Test kodu, bu kod yollarının her ikisi de çalışacak bir düz nesneyi oluşturmak ve kullanmak Sinon yöntemleri saplama.

// 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);

iddialarda bulunmak

SDK'yı başlattıktan, işlevleri sardıktan ve verileri oluşturduktan sonra, oluşturulmuş verilerle sarılmış işlevleri çağırabilir ve davranış hakkında iddialarda bulunabilirsiniz. Sen gibi bir kütüphane böyle kullanabilirsiniz Chai söz konusu iddiaları yapmak için.

Çevrimiçi modda iddialarda bulunma

Eğer Cloud Fonksiyonlar için Firebase Testi SDK başlatıldı Eğer çevrimiçi modda , (örneğin, bir veritabanı yazma gibi) istenen eylemler kullanarak gerçekleştiğini iddia edebilir firebase-admin SDK.

Aşağıdaki örnek, test projesinin veritabanına 'GİRDİ'nin yazıldığını ileri sürmektedir.

// 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 iddialarda bulunma

İşlevin beklenen getiri değeri hakkında iddialarda bulunabilirsiniz:

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 kullanılan olabilir Sinon casusları belli yöntemler çağrılmış bulunmadığını iddia edecek ve parametreleri ile beklediğiniz.

HTTP işlevlerini test etme

HTTP OnCall işlevlerini test etmek için aynı yaklaşım kullanmak arka plan fonksiyonlarını test .

HTTP onRequest fonksiyonlarını test ediyorsanız, kullanmak gerekir firebase-functions-test edin:

  • Sen kullanmak functions.config()
  • İşleviniz bir Firebase projesi veya diğer Google API'leri ile etkileşime giriyor ve testleriniz için gerçek bir Firebase projesi ve kimlik bilgilerini kullanmak istiyorsunuz.

Bir HTTP onRequest işlevi iki parametre alır: bir istek nesnesi ve bir yanıt nesnesi. Burada test edebilir nasıl addMessage() örnek fonksiyonu :

  • Çünkü cevap nesne yönlendirme fonksiyonunu geçersiz kıl sendMessage() çağırır.
  • Yönlendirme işlevi içinde, kullanım chai.assert yönlendirme fonksiyonunu parametreler ilgili olarak yardım yapmak iddialarının ile ç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 temizleme

Test kodunuzun en sonunda temizleme işlevini çağırın. O başlatıldı edildi ve SDK seti gerçek zamanlı veri tabanını oluşturmak için SDK'yı kullanılırsa oluşturulmuş olabilir Firebase uygulamaları siler o Bu unsets ortam değişkenleri DataSnapshot veya Firestore DocumentSnapshot .

test.cleanup();

Eksiksiz örnekleri inceleyin ve daha fazlasını öğrenin

Tam örnekleri Firebase GitHub deposunda inceleyebilirsiniz.

Daha fazla bilgi için bakınız API referansı için firebase-functions-test .